3977. 密码破译
题目
正解
快速判断长度为\(x\)的串是不是循环节,只需要判断\(len-x\)的串是否为区间的border。
哈希处理。
注意到如果\(x\)不是循环节,则它的因数都不会是循环节。
所以可以枚举\(x\)的质因子,长度除以质因子之后判断是不是,直到不是循环节为止,这样就可以得知最短循环节的这个质因子的指数。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 500010
#define ll long long
int n,m;
char s[N];
const int mo1=1000000007;
const int mo2=1000000009;
ll pw1[N],pw2[N],p1[N],p2[N];
void init(){
pw1[0]=pw2[0]=1;
for (int i=1;i<=n;++i){
pw1[i]=pw1[i-1]*26%mo1;
pw2[i]=pw2[i-1]*26%mo2;
}
for (int i=1;i<=n;++i){
p1[i]=(p1[i-1]*26+s[i]-'a')%mo1;
p2[i]=(p2[i-1]*26+s[i]-'a')%mo2;
}
}
bool eql(int x,int y,int len){
return ((p1[x+len-1]-p1[x-1]*pw1[len])%mo1+mo1)%mo1==((p1[y+len-1]-p1[y-1]*pw1[len])%mo1+mo1)%mo1
&& ((p2[x+len-1]-p2[x-1]*pw2[len])%mo2+mo2)%mo2==((p2[y+len-1]-p2[y-1]*pw2[len])%mo2+mo2)%mo2;
}
bool judge(int l,int r,int len){
len=r-l+1-len;
return eql(l,r-len+1,len);
}
int p[N],np;
bool inp[N];
int mnp[N];
int main(){
freopen("in.txt","r",stdin);
scanf("%d%s%d",&n,s+1,&m);
init();
for (int i=2;i<=n;++i){
if (!inp[i])
p[++np]=i,mnp[i]=i;
for (int j=1;j<=np && i*p[j]<=n;++j){
inp[i*p[j]]=1;
mnp[i*p[j]]=p[j];
if (i%p[j]==0)
break;
}
}
for (int i=1;i<=m;++i){
int l,r;
scanf("%d%d",&l,&r);
int len=r-l+1,ans=1;
while (len>1){
int q=mnp[len],tmp=r-l+1;
while (len%q==0 && judge(l,r,tmp/q))
len/=q,tmp/=q;
while (len%q==0)
len/=q,ans*=q;
}
printf("%d\n",ans);
}
return 0;
}