【POI2012】【BZOJ2795】A Horrible Poem

来源:互联网 发布:联想研究院 知乎 编辑:程序博客网 时间:2024/06/05 10:53

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 313using 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);}
0 0
原创粉丝点击