【bzoj2795】[Poi2012]A Horrible Poem hash

来源:互联网 发布:js原生与jquery 编辑:程序博客网 时间:2024/05/17 08:43

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

8aaabcabc31 33 84 8

Sample Output

135

HINT

Source

鸣谢 jiangzoi&oimaster


枚举约数是根号级的,算算复杂度好像过不了

有一个结论:若k是一个循环节,则pk也是一个循环节

于是把区间长度质因数分解,对于一个素数的指数ai,尽可能让它小,使得它再小就不是循环节为止。枚举指数是log级的。

O1判断是否是循环节可以hash

然后我写了个双hash,不过好像不需要?

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;const int SZ = 1000010;const int mod1 = 1000000007;const int mod2 = 998244353;int pri[SZ];char s[SZ];int h1[SZ],h2[SZ],n;int mi1[SZ],mi2[SZ];int gethash1(int l,int r){    int len = r - l + 1;    return (int)((h1[r] - (LL)h1[l - 1] * mi1[len] % mod1 + mod1) % mod1);}int gethash2(int l,int r){    int len = r - l + 1;    return (int)((h2[r] - (LL)h2[l - 1] * mi2[len] % mod2 + mod2) % mod2);}bool check(int l,int r,int len) //[l,l + len - 1]  [r - len + 1,r]{    int x = r - l + 1 - len;    int l1 = gethash1(l,l + x - 1),r1 = gethash1(r - x + 1,r);    int l2 = gethash2(l,l + x - 1),r2 = gethash2(r - x + 1,r);    return l1 == r1 && l2 == r2;}int ask_ans(int l,int r){    int ans = r - l + 1;    int x = r - l + 1;    for(int i = 2;i * i <= x;i ++)    {        while(ans % i == 0 && check(l,r,ans / i))            ans /= i;        while(x % i == 0) x /= i;    }    if(x != 1 && check(l,r,ans / x))        ans /= x;    return ans;}int main(){    scanf("%d",&n);    scanf("%s",s + 1);    mi1[0] = mi2[0] = 1;    for(int i = 1;i <= n;i ++)     {        mi1[i] = (LL)mi1[i - 1] * 233 % mod1;        mi2[i] = (LL)mi2[i - 1] * 10007 % mod2;    }    for(int i = 1;i <= n;i ++)    {        h1[i] = ((LL)h1[i - 1] * 233 % mod1 + s[i]) % mod1;        h2[i] = ((LL)h2[i - 1] * 10007 % mod2 + s[i]) % mod2;    }    int q;    scanf("%d",&q);    while(q --)    {        int l,r;        scanf("%d%d",&l,&r);        printf("%d\n",ask_ans(l,r));     }    return 0;}
0 0
原创粉丝点击