您的位置:首页 > 其它

【POI2012】【BZOJ2795】A Horrible Poem

2015-11-02 16:48 585 查看
Description

给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节。

如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到。

Input

第一行一个正整数n (n<=500,000),表示S的长度。

第二行n个小写英文字母,表示字符串S。

第三行一个正整数q (q<=2,000,000),表示询问个数。

下面q行每行两个正整数a,b (1<=a<=b<=n),表示询问字符串S[a..b]的最短循环节长度。

Output

依次输出q行正整数,第i行的正整数对应第i个询问的答案。

Sample Input

8

aaabcabc

3

1 3

3 8

4 8

Sample Output

1

3

5

HINT

Source

鸣谢 jiangzoi&oimaster

如果只有一个询问,显然直接KMP就可以

多个询问就hash吧

枚举循环长度,循环长度为询问长度的约数

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 500010
#define GET (ch>='0'&&ch<='9')
#define ULL unsigned long long
#define base 313
using namespace std;
char ch[MAXN];
int n,q;
int l,r,maxn;
int cnt[MAXN][30];
ULL Pow[MAXN],hash[MAXN];
int gcd(int a,int b)
{
return !b?a:gcd(b,a%b);
}
void in(int &x)
{
char ch=getchar();x=0;
while (!GET)    ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();
}
void check(int l,int r,int num)
{
int len=(r-l+1)-(r-l+1)/num;
ULL A=hash[l+len-1]-Pow[len]*hash[l-1],B=hash[r]-hash[r-len]*Pow[len];
if (A==B)   maxn=max(maxn,num);
}
void solve(int l,int r)
{
int divisor=r-l+1;maxn=0;
for (int i=0;i<26;i++)  divisor=gcd(divisor,cnt[r][i]-cnt[l-1][i]);
for (int i=1;i*i<=divisor;i++)
if (divisor%i==0)   check(l,r,i),check(l,r,divisor/i);
}
int main()
{
scanf("%d%s",&n,ch+1);Pow[0]=1;
for (int i=1;i<=n;i++)  hash[i]=hash[i-1]*base+ch[i]-'a'+1,Pow[i]=Pow[i-1]*base;
for (int i=1;i<=n;i++)
for (int j=0;j<26;j++)  cnt[i][j]=cnt[i-1][j]+(ch[i]-'a'==j);
in(q);
for (int i=1;i<=q;i++)  in(l),in(r),solve(l,r),printf("%d\n",(r-l+1)/maxn);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  字符串hash