P3538 [POI2012]OKR-A Horrible Poem

P3538 [POI2012]OKR-A Horrible Poem

hash+线性筛

题解 <----这篇写的不错(其实是我懒得码字了qwq)

UVA10298 Power Strings 的升级版

判断一个长为 u 的子串是否为 长为 n 的主串的循环子串 只要比较 [1,n-u ]和 [u+1, n]的hash值即可(所以说我以前都是瞎搞〒▽〒)

想了想,还是加点注释吧,不然为啥要写博客总结呢(逃

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
using namespace std;
typedef unsigned long long ull;
inline int Int(){
    char c=getchar(); int x=0;
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x;
}
const int base=19260817;
int n,q,cnt,v[500002],prime[500002],it_pri[500002];
char a[500002];
ull h1[500002],fac[500002]; //自然溢出hash
void get_prime(){ //线性筛筛素数
    for(int i=2;i<=n;++i){
        if(!v[i]) prime[++cnt]=v[i]=i;
        for(int j=1;j<=cnt;++j){
            if(prime[j]>v[i]||prime[j]>n/i) break;
            v[prime[j]*i]=prime[j];
        }
    }
}
inline bool check(int l1,int r1,int l2,int r2){ //hash值比较
    ull p1=h1[r1]-h1[l1-1]*fac[r1-l1+1];
    ull p2=h1[r2]-h1[l2-1]*fac[r2-l2+1];
    return p1==p2;
}
int main(){
    n=Int(); scanf("%s",a); fac[0]=1;
    for(int i=1;i<=n;++i){
        h1[i]=h1[i-1]*base+(ull)a[i-1];
        fac[i]=fac[i-1]*base;
    } //普通的hash
    get_prime();
    q=Int(); int l,r;
    for(int i=1;i<=q;++i){
        l=Int(); r=Int();
        int t=0,len=r-l+1;
        while(len>1) it_pri[++t]=v[len],len/=v[len]; //分解质因数
        len=r-l+1;
        for(int j=1;j<=t;++j){ 
            int u=len/it_pri[j];
            if(check(l,r-u,l+u,r)) len=u; //不断缩小循环子串的最小值
        }
        printf("%d\n",len);
    }
    return 0;
}

 

posted @ 2018-09-07 20:15  kafuuchino  阅读(289)  评论(0编辑  收藏  举报