[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 }

 

posted @ 2018-03-13 18:27  skylee03  阅读(129)  评论(0编辑  收藏  举报