-
题解:
- 询问区间的整循环节
- 设区间长度为$n$
- 如果有循环节长为$x$和$y$,那由斐蜀定理得$gcd(x,y)$也一定为一个循环节;
- 假设最小的循环节长为$mn$,那么对于任何循环节长$x$,一定$mn | x$ , 否则$gcd(mn,x)<mn$矛盾
- 推出$\frac{n}{x} | \frac{n}{mn}$
- 所以每次提出$n$的一个质因子$p$,考虑是否可以分成$p$段,如果可以$n=\frac{n}{p}$继续找;
- 最后得出来的$n$就是最短的循环节;
- 分解质因子可以$O(n)$线筛最大/最小质因子,$O(logn)$分解;
-
1 #include<bits/stdc++.h> 2 #define rg register 3 #define il inline 4 #define ull unsigned long long 5 #define base 1234567891 6 using namespace std; 7 const int N=500010; 8 int vis[N],pr[N],pt,v[N],n,m,len; 9 ull pw[N],h[N]; 10 char gc(){ 11 static char*p1,*p2,s[1000000]; 12 if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); 13 return(p1==p2)?EOF:*p1++; 14 } 15 int rd(){ 16 int x=0;char c=gc(); 17 while(c<‘0‘||c>‘9‘)c=gc(); 18 while(c>=‘0‘&&c<=‘9‘)x=(x<<1)+(x<<3)+c-‘0‘,c=gc(); 19 return x; 20 } 21 void pre(){ 22 for(rg int i=2;i<=n;i++){ 23 if(!vis[i])pr[++pt]=i,v[i]=i; 24 for(rg int j=1,t;j<=pt&&pr[j]*i<=n;j++){ 25 vis[t=i*pr[j]]=1; 26 v[t]=pr[j]; 27 if(i%pr[j]==0)break; 28 } 29 } 30 } 31 ull cal(int i,int j){return h[i+j-1] - h[i-1]*pw[j];} 32 int main(){ 33 #ifndef ONLINE_JUDGE 34 freopen("bzoj2795.in","r",stdin); 35 freopen("bzoj2795.out","w",stdout); 36 #endif 37 n=rd(); pre(); 38 char ch=gc();while(!isalpha(ch))ch=gc(); 39 for(rg int i=pw[0]=1;i<=n;i++,ch=gc()){ 40 h[i]=h[i-1]*base+ch; 41 pw[i]=pw[i-1]*base; 42 } 43 m=rd(); 44 for(rg int i=1,l,r;i<=m;i++){ 45 l=rd(); r=rd(); 46 int ans=r-l+1,now=ans,t; 47 while(now>1){ 48 t=ans/v[now]; 49 if(cal(l,ans-t)==cal(l+t,ans-t))ans/=v[now]; 50 now/=v[now]; 51 } 52 printf("%d\n",ans); 53 } 54 return 0; 55 }
bzoj2795
原文地址:https://www.cnblogs.com/Paul-Guderian/p/10241556.html
时间: 2024-10-10 16:47:20