求最小循环节,可以枚举最小循环节的长度 len ,然后判断 [a..b−len],[a+len,b] 的hash值是否相等。然后一开始写的 O(NN−−√) 的发现 TLE 了。然后我们发现,如果 len 是循环节,则 len×p 也是循环节 (len∗p|(b−a+1)) ,于是可以分解质因数,每次删去质因数就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define base 2333
#define N 500005
#define inf 1e9
using namespace std;
int n;
char s[N];
int mn[N],prime[N];
bool flag[N];
unsigned long long T[N],hash[N];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline unsigned long long gethash(int l,int r)
{
return hash[r]-hash[l-1]*T[r-l+1];
}
inline bool check(int st,int en,int len)
{
int total=en-st+1;
if (gethash(st,st+total-len-1)==gethash(st+len,en)) return true;
return false;
}
inline void pre()
{
for (int i=2;i<=n;i++)
{
if (!flag[i]) prime[++prime[0]]=i,mn[i]=i;
for (int j=1;j<=prime[0]&&i*prime[j]<=n;j++)
{
flag[i*prime[j]]=1;
mn[i*prime[j]]=prime[j];
if (i%prime[j]==0) break;
}
}
}
int main()
{
n=read();
pre();
scanf("%s",s+1);
T[0]=1;
for (int i=1;i<=n;i++)
T[i]=T[i-1]*base;
for (int i=1;i<=n;i++)
hash[i]=hash[i-1]*base+s[i]-'a'+1;
int query=read();
while (query--)
{
int a=read(),b=read();
int len=b-a+1;
int x=len;
while (x>1)
{
int y=mn[x];
while (len%y==0&&check(a,b,len/y)) len/=y;
while (x%y==0) x/=y;
}
printf("%d\n",len);
}
return 0;
}