bzoj2795 [POI2012]OKR-A Horrible Poem[字符串hash]
蒟蒻第一次写字符串hash
瑟瑟发抖
简述题意:给你一个字符串,每次 询问你一个区间内字符串的最小循环节长度为多少
循环节有三个有趣的性质:
- 循环节长度一定是序列长度的约数
- 循环节的倍数还是循环节
- 对于区间 ,如果 ,则 就是一个循环节
那么这道题就是个简单的题目了
首先线性筛,处理出质数,然后对于每个询问对区间长度分解质因数,大力比较 hash值就可以了
复杂度不清楚,但一定比
优得多,那就
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1000010;
typedef unsigned long long gay;
const gay base=19260817;
gay _hash[MAXN],bin[MAXN];
int n,prime[MAXN],cnt,pos[MAXN],Q,lsq[MAXN],top;
char s[MAXN];
bool notprime[MAXN];
inline void geigei()
{
for(register int i=2;i<=n;i++)
{
if(!notprime[i])prime[++cnt]=i,pos[i]=i;
for(register int j=1;j<=cnt&&prime[j]*i<=n;j++)
{
notprime[i*prime[j]]=true;
pos[i*prime[j]]=prime[j];
if(i%prime[j]==0)break;
}
}
}
int main()
{
scanf("%d%s",&n,s+1);
bin[0]=1;
for(register int i=1;i<=n;i++)
_hash[i]=_hash[i-1]*base+s[i]-'a',bin[i]=bin[i-1]*base;
scanf("%d",&Q);
geigei();
while(Q--)
{
int l,r;
scanf("%d%d",&l,&r);
int len=r-l+1;
top=0;
while(len^1){lsq[++top]=pos[len],len/=pos[len];}
len=r-l+1;
for(register int i=1;i<=top;i++)
{
int temp=len/lsq[i];
if(_hash[r-temp]-bin[r-temp-l+1]*_hash[l-1]==_hash[r]-bin[r-temp-l+1]*_hash[l+temp-1])
len=temp;
}
printf("%d\n",len);
}
}