洛谷P3538 [POI2012] OKR-A Horrible Poem

前言

比较典,可以当模板题,故记录一下,写的可能比较水。

题意

Link

长度为 \(n\ (\leq 6\times 10^5)\) 的字符串,有 \(q\ (\leq 2\times 10^6)\) 个询问,每次询问求一个区间的最小循环节。

思路

题面看起来很唬人,我们平时求最短循环节都是用前缀函数,这一放在区间上就不会做了。

但实际上很简单,最小循环节的长度一定是串长的因数,因此直接枚举即可,用线性筛记录每个数最大的质因数来优化,不断除以自己最大的质因数即可枚举所有因数。

至于判断一个长度是否为循环节,可以用哈希,设长度为 \(len\),如果 \(\operatorname{Substr}[l,r-len]=\operatorname{Substr}[l+len,r]\) 则说明该长度为循环节长度。

复杂度当然就是 \(O(q\cdot d(n))\),这个 \(d(n)\) 就很玄学,据说可以证明最多 \(O(\sqrt n)\),但实际经常跑不满,反正卡常题。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=5e5,MAXQ=2e6;
LL bs=13131,bspw[MAXN+5],P=1e9+321;
int n,q;
char str[MAXN+5];

inline void init_bspw(){
    bspw[0]=1;
    for(int i=1;i<=n;i++)
        bspw[i]=bspw[i-1]*bs%P;
}
struct HashNode{
    LL val;
    int len;
    HashNode(){}
    HashNode(LL a,int b):val(a),len(b){}
};
inline HashNode operator + (const HashNode& a,const HashNode& b){
    HashNode res;
    res.val=(a.val*bspw[b.len]%P+b.val)%P;
    res.len=a.len+b.len;
    return res;
}
inline HashNode operator - (const HashNode& a,const HashNode& b){//b is prefix of a
    HashNode res;
    res.val=(a.val-b.val*bspw[a.len-b.len]%P+P)%P;
    res.len=a.len-b.len;
    return res;
}
inline bool operator == (const HashNode& a,const HashNode& b){
    return (a.len==b.len) && (a.val==b.val);
}
class HashString{
private:
    HashNode hs[MAXN+5];
public:
    inline void build(){
        hs[0]=HashNode(0,0);
        for(int i=1;i<=n;i++)
            hs[i]=HashNode(str[i]-'a'+1,1);
        for(int i=1;i<=n;i++)
            hs[i]=hs[i-1]+hs[i];
    }
    inline HashNode query(const int& l,const int& r) const{
        return hs[r]-hs[l-1];
    }
}hs;

vector<int>prime;
bool vis[MAXN+5];
int divisor[MAXN+5];
inline void init_prime(){
    for(int i=2;i<=n;i++){
        if(!vis[i]) prime.push_back(i),divisor[i]=i;
        for(auto it:prime){
            if(1LL*it*i>n) break;
            vis[it*i]=true;
            divisor[it*i]=it;
            if(i%it==0) break;
        }
    }
}

inline bool check(int l,int r,int len){
    return hs.query(l,r-len)==hs.query(l+len,r);
}

int main(){
    scanf("%d",&n);
    scanf("%s",str+1);
    init_bspw();
    init_prime();
    hs.build();

    scanf("%d",&q);
    int l,r,len,tmp;
    while(q--){
        scanf("%d %d",&l,&r);
        len=tmp=r-l+1;
        while(tmp>1){
            if(check(l,r,len/divisor[tmp])) len/=divisor[tmp];
            tmp/=divisor[tmp];
        }
        printf("%d\n",len);
    }
    return 0;
}
posted @ 2024-11-18 12:12  MessageBoxA  阅读(2)  评论(0编辑  收藏  举报