And echo|

MessageBoxA

园龄:4年10个月粉丝:4关注:0

洛谷P3538 [POI2012] OKR-A Horrible Poem

前言

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

题意

Link

长度为 n (6×105) 的字符串,有 q (2×106) 个询问,每次询问求一个区间的最小循环节。

思路

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

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

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

复杂度当然就是 O(qd(n)),这个 d(n) 就很玄学,据说可以证明最多 O(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;
}

本文作者:MessageBoxA

本文链接:https://www.cnblogs.com/SkyNet-PKN/p/18552310

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   MessageBoxA  阅读(5)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 evening Corn Wave
  2. 2 Группа крови Кино
  3. 3 The Sound Of Silence Simon & Garfunkel
  4. 4 dB doll YUE.STEVEN
The Sound Of Silence - Simon & Garfunkel
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.