思路
把长度为n的字符串分解成多个同构循环子串,这题是直接暴力求n的因子个数,每个因子看可不可分解,用哈希值存储第一个子串的同构循环子串,进行比较。
这题主要是同构循环子串是怎么设定哈希值的比较烦,直接记下模版吧。
题解代码来源
#include<bits/stdc++.h>
#define ll long long
using namespace std;
using namespace std;
const int mod=1e7+7;
const int base=1331;
const int N=5e6+10;
int T;
int n;
char s[N];
int p[N],a[N];
int jl[mod];
int js(int l,int r) { // 子串哈希值
return (a[r]-1ll*a[l-1]*p[r-l+1]%mod+mod)%mod;
}
int tot=0; //时间戳
bool pd(int k,int id) {
if(k==1) return 0;
int len=n/k;
int l=1,r=len;
jl[js(1,len)]=id;
for(int i=1;i<len;i++) {
int temp1=(1ll*js(i+1,len)*p[i]%mod+js(1,i))%mod;
jl[temp1]=id;//将循环同构子串标记为相同
}
// printf("len=%d\n",len);
for(int i=1;i<=k;i++) {
int temp=js(l,r);
// printf("temp=%d,jl=%d\n",temp,jl[temp]);
if(jl[temp]!=id) return 0; // 不是子集
l+=len,r+=len;
}
return 1;
}
int main()
{
//cwk;
scanf("%d",&T);
p[0]=1;
for(int i=1;i<N;i++) p[i]=(1ll*p[i-1]*base)%mod;
while(T--) {
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;i++) {
a[i]=(1ll*a[i-1]*base%mod+(s[i]-'a'+1))%mod;
}
int flag=0;
for(int i=1;1ll*i*i<=1ll*n&&!flag;i++) { // 根号枚举因数
if(n%i==0) {
flag|=pd(i,++tot);
flag|=pd(n/i,++tot);
}
}
if(!flag) puts("No");
else puts("Yes");
}
return 0;
}