题目大意
见题面……
解题分析
贴结论:一个字符串的最小周期等于这个字符串的长度-border的长度
但这道题是多组询问,所以不能用KMP,此时又出现了这么一个定理:如果这个字符串的一个周期为x,则[L,R-x]=[L+x,R] ([]表示子串位置)
而且很明显循环节的长度是字符串的一个因子。
所以线性筛O( n−−√ n )找出所有因子,然后哈希判断一下就行了…
#include<cstdio>
#include<cstring>
#include<algorithm>
#define bse 139
#define maxn 500005
using namespace std;
typedef unsigned long long LL;
int n,q,p[maxn],d[maxn];
LL pw[maxn],hsh[maxn];
char a[maxn];
bool vs[maxn];
inline void readi(int &x){
x=0; char ch=getchar();
while ('0'>ch||ch>'9') ch=getchar();
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
void makep(){
p[0]=0; memset(vs,1,sizeof(vs));
for (int i=2;i<=n;i++){
if (vs[i]) {p[++p[0]]=i; d[i]=i;}
for (int j=1;j<=p[0]&&i*p[j]<=n;j++){
vs[i*p[j]]=0; d[i*p[j]]=p[j];
if (i%p[j]==0) break;
}
}
}
bool _check(int L,int R,int l,int r){
LL ha=hsh[R]-hsh[L-1]*pw[R-L+1],hb=hsh[r]-hsh[l-1]*pw[r-l+1];
return ha==hb;
}
int _Ask(int L,int R){
int len=R-L+1,ans=len;
while (len!=1){
int cur=d[len];
while (ans%cur==0&&_check(L,R-ans/cur,L+ans/cur,R)) ans/=cur;
while (len%cur==0) len/=cur;
}
return ans;
}
int main()
{
freopen("poem.in","r",stdin);
freopen("poem.out","w",stdout);
readi(n); scanf("%s",a+1); readi(q);
makep(); pw[0]=1;
for (int i=1;i<=n;i++) {hsh[i]=hsh[i-1]*bse+a[i]-'a'+1; pw[i]=pw[i-1]*bse;}
while (q--){
int x,y; readi(x); readi(y);
printf("%d\n",_Ask(x,y));
}
return 0;
}