您的位置:首页 > 其它

[BZOJ 2795]POI2012 A Horrible Poem

2014-12-17 22:01 267 查看
很优美的题目:)

列出以下性质:

1、循环节一定是长度的约数(废话。。。)

2、如果n是一个循环节,那么k*n也必定是一个循环节(关键所在)

3、n是[l,r]这一段的循环节 的充要条件是 [l,r-n]和[l+n,r]相同(利用这个性质我们在判断是否为循环姐是可以做到O(1))

我们从性质2开始,如果len是循环节,那么最小循环节一定是len的约数——是不是有想法了?

枚举所有的质因子,不断除以原长并保证其仍是循环节,直到不能再小为止。

复杂度O(nlogn)(常数很小)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int Maxn=500005, MaxP=(1e9)+7;
char ch;
int n,pow[Maxn],i,j,l,r,len,m;
int check[Maxn],prime[Maxn],hash[Maxn],tot;

int read(){
char ch=getchar();
int ret=0;
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9')
{ret=ret*10+ch-'0'; ch=getchar();}
return ret;
}

void init(){
for (i=2;i<Maxn;i++){
if (check[i]==0) check[i]=i, prime[++tot]=i;
for (j=1;j<=tot;j++){
if (i*prime[j]>=Maxn) break;
check[i*prime[j]]=prime[j];
if (i%prime[j]==0) break;
}
}
}

bool equal(int l1,int r1,int l2,int r2){
int t1=hash[r1]-hash[l1-1]*pow[r1-l1+1];
int t2=hash[r2]-hash[l2-1]*pow[r2-l2+1];
return (t1==t2);
}

int main(){
freopen("okr.in","r",stdin);
freopen("okr.out","w",stdout);
init();
scanf("%d\n",&n);
for (i=1,pow[0]=1;i<=n;i++)
pow[i]=pow[i-1]*MaxP;
for (i=1;i<=n;i++){
ch=getchar();
hash[i]=hash[i-1]*MaxP+ch;
}
m=read();
while (m--){
l=read(); r=read();
len=r-l+1;
for (i=len;i>1;){
j=check[i];
while ( len%j==0 && equal(l,r-len/j,l+len/j,r) ) len/=j;
while (i%j==0) i=i/j;
}
printf("%d\n",len);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: