题意
给一个字符串 (s) ,长度为 (n) ,问是否存在一个 (k) ,满足 (k∣n) ,将 (s) 分成相等的 (k) 段子串,每一段子串互为循环同构。其中,(1≤T≤1000,1≤n≤5⋅10^6, sum{n}leq2⋅10^7)。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6863
分析
枚举 (n) 的所有满足条件的因子,然后对于每一个长度 (d),求出 ([1,d]) 的所有循环同构的字符串的 ( ext{Hash}) 值,进行标记,然后再遍历原字符串,求出划分后的其它所有子串是否满足循环同构。
已知 ( ext{Hash[i]}) 和 ( ext{Hash[j]}) ,其中 (i<j),求 ([i+1,j]) 子串的 ( ext{Hash}) 值:
[ ext{ans}=( ext{Hash[j]}- ext{Hash[i]}· ext{base}^{j-i} \% mod+mod)\% mod
]
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=12582917;
const int N=5e6+6;
const int maxn=2e7;
const int base=1543;
char ss[N];
int Hash[N],por[N];
int id[maxn],cnt;
void init()
{
por[0]=1;
for(int i=1;i<N;i++)
por[i]=1LL*por[i-1]*base%mod;
}
void get_hash(int len)
{
for(int i=1;i<=len;i++)
Hash[i]=(1LL*Hash[i-1]*base%mod+ss[i])%mod;
}
bool solve(int d,int len)
{
++cnt;
int tmp=Hash[d];
id[tmp]=cnt;
for(int i=1;i<=d;i++)//同构的其它串的hash值
{
tmp=(tmp-1LL*ss[i]*por[d-1]%mod+mod)%mod;
tmp=(1LL*tmp*base+ss[i])%mod;
id[tmp]=cnt;
}
for(int i=d+d;i<=len;i+=d)
{
int x=(Hash[i]-1LL*Hash[i-d]*por[d]%mod+mod)%mod;
if(id[x]!=cnt) return false;
}
return true;
}
int main()
{
int T,n;
init();
scanf("%d",&T);
cnt=0;
while(T--)
{
scanf("%d",&n);
scanf("%s",ss+1);
get_hash(n);
bool f=0;
for(int i=2;i*i<=n;i++)//每一段的长度
{
if(n%i) continue;
int t=n/i;
f=solve(i,n);
if(f) break;
if(i!=t) f=solve(t,n);
if(f) break;
}
if(f==0&&n>1) f=solve(1,n);
if(f) printf("Yes
");
else printf("No
");
}
return 0;
}