[POI2012]A Horrible Poem
题目大意:
给定一个长度为$n(n\leq5\times10^5)$的字符串$S$,$q(q\leq2\times10^6)$组询问,每次询问子串$S_{[l_i,r_i]}$最小循环节。
思路:
若$i$是循环节,则最小循环节一定是$i$的因数。因此可以线性筛预处理出$1\sim n$每个数的最大质因数,然后根据情况用当前因数去除当前答案,不断枚举出其它的一些可能的答案即可。
1 #include<cstdio> 2 #include<cctype> 3 typedef unsigned long long uint64; 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=500001,BASE=31; 12 char s[N]; 13 bool vis[N]; 14 uint64 pow[N],h[N]; 15 int n,div[N],p[N]; 16 inline void sieve() { 17 for(register int i=2;i<=n;i++) { 18 if(!vis[i]) { 19 div[i]=p[++p[0]]=i; 20 } 21 for(register int j=1;j<=p[0]&&p[j]*i<=n;j++) { 22 vis[i*p[j]]=true; 23 div[i*p[j]]=p[j]; 24 if(i%p[j]==0) break; 25 } 26 } 27 } 28 inline uint64 hash(const int &l,const int &r) { 29 return h[r]-h[l-1]*pow[r-l+1]; 30 } 31 int main() { 32 n=getint(); 33 scanf("%s",s); 34 for(register int i=pow[0]=1;i<=n;i++) { 35 pow[i]=pow[i-1]*BASE; 36 h[i]=h[i-1]*BASE+s[i-1]-'a'; 37 } 38 sieve(); 39 for(register int i=getint();i;i--) { 40 const int l=getint(),r=getint(); 41 int ans=r-l+1; 42 for(register int i=ans;i!=1;) { 43 int j=div[i]; 44 while(ans%j==0&&hash(l,r-ans/j)==hash(l+ans/j,r)) ans/=j; 45 while(i%j==0) i/=j; 46 } 47 printf("%d\n",ans); 48 } 49 return 0; 50 }