题解:AT_cf17_final_e Combination Lock
题目
给定长度为
思路
首先将回文的要求转化一下。设
然后构建差分数组
由于操作不限次数,这相当于在两点间连边,允许自由转移值。可转化为用并查集维护连通块:
- 初始状态:计算所有
b_i 并初始化并查集。 - 合并转移:遍历所有操作
[l, r] ,利用映射idx(x) = \min(x+1, m-x+1) ,将点idx(l-1) 与idx(r) 合并。 - 判定条件:累加每个连通块内的
b_i 。若所有连通块均满足\sum b \equiv 0 \pmod{26} ,则可通过内部转移归零。
最后根据连通块的和是否全为
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
string str;
const int N=1e5+5;
int t,n,m;
int fa[N],sum[N],d[N],b[N];
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int idx(int x){
return min(x+1,m-x+1);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>t;
while(t--){
cin>>str>>n;
m=str.size();
str=" "+str;
int k=m/2;
d[0]=d[k+1]=0;
for(int i=1;i<=k;i++)
d[i]=(str[m-i+1]-str[i]+26)%26;
for(int i=1;i<=k+1;i++){
b[i]=(d[i]-d[i-1]+26)%26;
fa[i]=i;
sum[i]=0;
}
for(int i=1;i<=n;i++){
int l,r;
cin>>l>>r;
int u=find(idx(l-1)),v=find(idx(r));
if(u!=v)
fa[u]=v;
}
for(int i=1;i<=k+1;i++)
sum[find(i)]=(sum[find(i)]+b[i])%26;
int flag=1;
for(int i=1;i<=k+1;i++){
if(fa[i]==i&&sum[i]!=0){
cout<<"NO\n";
flag=0;
break;
}
}
if(flag)
cout<<"YES\n";
}
return 0;
}