BZOJ2795 [Poi2012]A Horrible Poem
题面在这里
其实挺简单的……
考虑\(S[1..x]\)是S的循环节,当且仅当\(S[1..n-x]=S[1+x,n]\)
这个可以用哈希快速判断
因为循环节一定是最小循环节的倍数,而n一定是S的循环节
那么就可以从n开始,枚举并排除质因子,从而得到最小质因子
这个用线性筛预处理最小质因子\(O(logn)\)枚举就好了
示例程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include<cstdio> #define ull unsigned long long
const int maxn=500005; int n,q,p[maxn],nxt[maxn]; bool vis[maxn]; char s[maxn]; void makep(int n){ nxt[1]=1; for (int i=2;i<=n;i++){ if (!vis[i]) p[++p[0]]=i,nxt[i]=i; for (int j=1;j<=p[0]&&i*p[j]<=n;j++){ vis[i*p[j]]=1;nxt[i*p[j]]=p[j]; if (i%p[j]==0) break; } } } ull sum[maxn],pw[maxn]; inline ull getha(int l,int r){ if (l>r) return 0; return sum[r]-sum[l-1]*pw[r-l+1]; } int main(){ scanf("%d%s",&n,s+1);makep(n);pw[0]=1; for (int i=1;i<=n;i++) sum[i]=sum[i-1]*233+s[i],pw[i]=pw[i-1]*233; scanf("%d",&q); while (q--){ int l,r,tem,len,mn;scanf("%d%d",&l,&r); for (tem=len=r-l+1,mn=nxt[tem];tem>1;mn=nxt[tem]){ while (len%mn==0&&getha(l,r-len/mn)==getha(l+len/mn,r)) len/=mn; while (tem%mn==0) tem/=mn; } printf("%d\n",len); } return 0; }
|