分析:
这是今天下午的考试题,推了2个小时,考试中A掉了
首先,循环串通过字符串hash可以O(1)判断:get_hash(l,r-len)==get_hash(l+len,r);显然可证。
我们其次可以发现,循环串的长度是所求串的长度的约数
之后我们可以发现,如果两个不同的子串是循环串,那么这两个子串长度的gcd也一定是循环串。
那么,我们就可以发现,将长度质因数分解,之后每次判断长度/这个质因子的所得长度能否构成循环串,如果能,就将长度除以这个质因子。
至于质因子,我们可以线筛...详情自己去分析,或者去看下面的代码...懒得讲了...
附上代码:
#include <cstdio> #include <cmath> #include <iostream> #include <queue> #include <algorithm> #include <cstring> #include <cstdlib> using namespace std; #define N 500005 #define Base 131 #define ll unsigned long long char s[N]; ll hash[N],b[N]; int n,Q,ans[N],pri[N],vis[N],last[N],cnt; ll get_hash(int x,int y) { return hash[y]-hash[x-1]*b[y-x+1]; } void init() { for(int i=2;i<=n;i++) { if(!vis[i]) { pri[++cnt]=i; last[i]=i; } for(int j=1;j<=cnt&&i*pri[j]<=n;j++) { vis[pri[j]*i]=1;last[pri[j]*i]=pri[j]; if(!(i%pri[j]))break; } } } int que[N]; int main() { //freopen("str.in","r",stdin); //freopen("str.out","w",stdout); scanf("%d",&n); init(); scanf("%s",s+1); b[0]=1; for(int i=1;i<=n;i++)b[i]=b[i-1]*Base; for(int i=1;i<=n;i++) { hash[i]=hash[i-1]*Base+s[i]-'a'; } scanf("%d",&Q); while(Q--) { int a,b; scanf("%d%d",&a,&b); int len=b-a+1;int t=len,tot=0; if(len==1) { puts("1"); continue; } while(t!=1) { que[++tot]=last[t]; t=t/last[t]; } for(int i=1;i<=tot;i++) { t=len/que[i]; if(get_hash(a,b-t)==get_hash(a+t,b))len=len/que[i]; } printf("%d ",len); } return 0; }
Orz O(n*sqrt(n))的时间也能过...暴力踩标程...