2023“钉耙编程”中国大学生算法设计超级联赛(1)Cyclically Isomorphic
题目大意
如果存在一个整数 k k k,使得字符串 S S S在循环右移 k k k位之后与字符串 T T T相同,则称 S S S和 T T T是循环同构关系。
现在,给定一个由 n n n个小写字母组成的长度为 m m m的字符串,以及 Q Q Q次查询,每次查询给出两个正整数 x , y x,y x,y。如果字符串 s x s_x sx和 x y x_y xy是循环右移关系,则输出 Y e s Yes Yes;否则,输出 N o No No。
有 t t t组数据。
1 ≤ t ≤ 5 , 1 ≤ n × m ≤ 1 0 5 , 1 ≤ Q ≤ 1 0 5 1\leq t\leq 5,1\leq n\times m\leq 10^5,1\leq Q\leq 10^5 1≤t≤5,1≤n×m≤105,1≤Q≤105
题解
对于每一个字符串,我们可以将其复制一份并放在字符串末尾,再求出每一个位置开始的 m m m个位置的哈希值。
如果 s x s_x sx和 s y s_y sy是循环同构关系,则 s y s_y sy的哈希值肯定与 s x s_x sx经上述操作后的 m m m个哈希值中的一个相同。对于每次询问,我们判断 s y s_y sy的哈希值是否在 s x s_x sx经上述操作后的 m m m个哈希值中出现,那么 S S S和 T T T是循环同构关系;否则 S S S和 T T T不是循环同构关系。
时间复杂度为 O ( n × m log m + Q log m ) O(n\times m\log m+Q\log m) O(n×mlogm+Qlogm)。
code
#include<bits/stdc++.h>
using namespace std;
const long long mod=998244353;
int t,n,m,q,x,y;
string s;
long long td,now,v[100005];
vector<long long>st[100005];
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
td=1;
for(int i=1;i<=m;i++) td=td*26%mod;
for(int i=1;i<=n;i++){
cin>>s;
s=s+s;
now=0;
for(int j=0;j<2*m;j++){
now=(now*26+s[j]-'a')%mod;
if(j>=m) now=(now-(s[j]-'a')*td%mod+mod)%mod;
st[i].push_back(now);
if(j==m-1) v[i]=now;
}
sort(st[i].begin(),st[i].end());
}
scanf("%d",&q);
while(q--){
scanf("%d%d",&x,&y);
vector<long long>::iterator it=lower_bound(st[x].begin(),st[x].end(),v[y]);
if(*it==v[y]) printf("Yes\n");
else printf("No\n");
}
for(int i=1;i<=n;i++){
v[i]=0;
st[i].clear();
}
}
return 0;
}