很edu的一场,建议全部补完喵~。
A.回文(version 1)
按题意模拟一下即可。
注意题目给的是 不是
。
时间复杂度 。
n = int(input())
def f(x):
return str(x) == str(x)[::-1]
print("YES" if f(n) and f(int(n**0.5)) and int(n**0.5) == n**0.5 else "NO")
B.未知(version 1)
由于 ,因此
,取
即可。
时间复杂度 。
for _ in range(int(input())):
print(input().split()[1])
C.回文(version 2)
不妨考虑从外往内匹配。
如果两个字符相同,则两段指针直接内移,否则尝试两个 和
匹配即可。
时间复杂度 。
void solve(){
string s;cin>>s;
ll l = 0, r = s.size()-1;
while(l<=r){
if(s[l]==s[r]){
l++,r--;
}
else if(s[l]=='n'){
if(s[l+1]=='n') l+=2,r--;
else{
cout<<"NO\n";
return;
}
}
else{
if(s[r-1]=='n') r-=2,l++;
else{
cout<<"NO\n";
return;
}
}
}
cout<<"YES\n";
}
D.未知(version 2)
考虑对所有 预处理所有的
满足
,但是至少有
(
) 对。
注意到当 时,只有
一对满足要求的,因此这一部分可以直接判断而不预处理。
剩下的对数,共有 对,可以直接预处理出来。
则对于每个 ,我们检查所有满足
:
- 如果
则其他元素里必须有两个
。
- 否则其他元素里必须有一个
和一个
。
时间复杂度 。
unordered_map<ll, vector<PLL>> memo;
ll c = 0;
void init(){
memo[1].pb({1, 1});
for(ll i=2;i*i<=1e9;i++){
ll cur = i;
ll cnt = 1;
c++;
while(cur<=1e9){
cur*=i;
cnt++;
memo[cur].pb({i, cnt});
c++;
}
}
}
void solve(){
ll n = read();
vector<ll> a(n);
unordered_map<ll, ll> memo2;
for(ll i=0;i<n;i++) a[i] = read(), memo2[a[i]]++;
for(ll i=0;i<n;i++){
memo2[a[i]]--;
for(auto [t, p]:memo[a[i]]){
if(t==p&&memo2[t]>=2){
puts("YES");
return;
}
else if(memo2[t]&&memo2[p]){
puts("YES");
return;
}
}
if(a[i]*a[i]>1e9){
if(memo2[1]&&memo2[a[i]]){
puts("YES");
return;
}
}
memo2[a[i]]++;
}
puts("NO");
}
E.未知(version 3)
考虑边界情况,不妨考虑从距离 以此接上去(具体可见下图):
- 如果每个叶子结点都是由根节点接一条链到达距离
的,则需要
个点。
- 如果每个叶子结点尽可能和其他链复用节点,若已经有了
距离的节点,则至少从
的链末尾的父节点开始接(否则会把叶子结点变没)。此时新增两个节点,因此需要
个点。
则 均可以构造,否则不能。
不妨考虑先把距离为 的那条链构造出来作为主链,在从距离
依次接上去。
此时需要在主链上复用的节点数量为 。
对于距离为 的点,最多可以复用
个节点,在从主链上
节点的位置开始接。
时间复杂度 。
void solve(){
ll n = read(), m = read();
if(!(2*m<=n&&n<=1+(1+m)*m/2)){
puts("NO");
return;
}
puts("YES");
for(ll i=2;i<=m+1;i++){
print(PLL{i, i-1});
}
ll need = 1+(1+m)*m/2 - n;
ll cur = m+2;
for(ll i=1;i<m;i++){
ll use = min(i-1, need);
need -= use;
ll pre = use + 1;
for(ll j=use+1;j<=i;j++){
print(PLL{pre, cur});
pre = cur;
cur++;
}
}
}
F.回文(version 3)
不妨将三种情况分开讨论。
-
显然答案即为
。
-
答案即为相同字符的匹配对数,答案即为
。
-
还需要在相同字符见插入一个字母。
设对于某个字符
内有
个节点,则该字符的贡献为:
考虑如何通过前缀预处理
得到这个答案。(以单个字符为例,显然不同字符之间的答案可以直接累加)
设
有
个字符,
所有字符的位置之和为
不妨先求
的字符答案,设为
。
则对于新增一个位置
,答案的变化值为
。
再考虑如何求解
的答案。
如果直接
,会多计算
和
匹配的部分。
对于
内的每个元素,多计算了
,求和得到
因此
内的答案为
时间复杂度 。
void solve(){
ll n, q;cin>>n>>q;
string s;cin>>s;
s = ' ' + s;
vector<vector<ll>> pre(n+1, vector<ll>(26));// cnt
for(ll i=1;i<=n;i++){
for(ll j=0;j<26;j++){
pre[i][j] = (pre[i-1][j] + ((s[i]-'a')==j));
}
}
vector<vector<ll>> pre2(n+1, vector<ll>(26));// psum
for(ll i=1;i<=n;i++){
for(ll j=0;j<26;j++){
pre2[i][j] = (pre2[i-1][j] + ((s[i]-'a')==j)*i);
}
}
vector<vector<ll>> pre3(n+1, vector<ll>(26));// ans
for(ll i=1;i<=n;i++){
for(ll j=0;j<26;j++){
pre3[i][j] = pre3[i-1][j];
if((s[i]-'a')==j){
pre3[i][j] += (i-1)*pre[i-1][j]-pre2[i-1][j];
}
}
}
while(q--){
ll l, r, x;cin>>l>>r>>x;
if(x == 1) cout<<r-l+1<<'\n';
else if(x == 2){
ll ans = 0;
for(ll i=0;i<=25;i++) ans += (pre[r][i] - pre[l-1][i])*((pre[r][i] - pre[l-1][i])-1)/2;
cout<<ans<<'\n';
}
else{
ll ans = 0;
for(ll i=0;i<=25;i++){
ans += (pre3[r][i]-pre3[l-1][i]);
ans -= pre[l-1][i]*((pre2[r][i]-pre2[l-1][i])-(pre[r][i]-pre[l-1][i]))-(pre[r][i]-pre[l-1][i])*pre2[l-1][i];
}
cout<<ans<<'\n';
}
}
}

京公网安备 11010502036488号