首页 > 其他分享 >洛谷P3538 [POI2012] OKR-A Horrible Poem

洛谷P3538 [POI2012] OKR-A Horrible Poem

时间:2024-11-18 12:06:59浏览次数:1  
标签:tmp Poem OKR 洛谷 divisor int len init MAXN

前言

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

题意

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;
}

标签:tmp,Poem,OKR,洛谷,divisor,int,len,init,MAXN
From: https://www.cnblogs.com/SkyNet-PKN/p/18552310

相关文章

  • 洛谷 P3226 [HNOI2012] 集合选数 做题记录
    我们先建一个矩阵:\(\begin{bmatrix}1&2&4&8&16&32\\3&6&12&24&48&96\\9&18&36&72&144&288\\27&54&108&216&432&864\end{bmatrix}\)......
  • 洛谷题单指南-二叉堆与树状数组-P3368 【模板】树状数组 2
    原题链接:https://www.luogu.com.cn/problem/P3368题意解读:树状数组应用-区间修改,单点求值解题思路:设原数组为s[N],其差分数组为a[N]操作一:区间修改要对s[x]~s[y]每个数增加k,相当于对a[x]加k,对a[y+1]减k,O(n)的操作变成了O(1)的操作,利用树状数组tr[N]的add(x,k),add(y+......
  • 洛谷题单指南-二叉堆与树状数组-P3374 【模板】树状数组 1
    原题链接:https://www.luogu.com.cn/problem/P3374题意解读:树状数组模版:单点修改,区间求值。解题思路:树状数组-BinaryIndexTree可以动态维护一组数,可以O(logn)的修改一个数,也可以O(logn)的计算一段区间的和。思考一下朴素做法:如何修改一个数,计算区间和?如果是常规数组,修改操作......
  • 洛谷P1607
    [NOIP2009普及组]多项式输出-洛谷 [NOIP2009普及组]多项式输出题目描述一元n次多项式可用如下的表达式表示:f(x)=a_nx^n+a_{n-1}x^{n-1}+\cdots+a_1x+a_0,a_n\ne0其中,a_ix^i称为i次项,a_i称为i 次项的系数。给出一个一元多项式各项的次数和系数,请按照如下规定......
  • CSP/信奥赛C++语法基础刷题训练(11):洛谷P5743:猴子吃桃
    CSP/信奥赛C++语法基础刷题训练(11):洛谷P5743:猴子吃桃题目描述一只小猴买了若干个桃子。第一天他刚好吃了这些桃子的一半,又贪嘴多吃了一个;接下来的每一天它都会吃剩余的桃子的一半外加一个。第n......
  • CSP/信奥赛C++语法基础刷题训练(12):洛谷P1047:[NOIP2005 普及组] 校门外的树
    CSP/信奥赛C++语法基础刷题训练(12):洛谷P1047:[NOIP2005普及组]校门外的树题目描述某校大门外长度为lll的马路上有一排树,每两棵相邻的树之间的间隔都是......
  • 洛谷 P6874 [COCI2013-2014#6] KOCKICE
    动笔算算样例可得一个性质,只要确定中间位置的数是多少,其他位置就可以直接求出。如果我们暴枚中间的数,必然超时。于是我们需要用二分。如果中间位置上的数是答案,那么无论什么数,操作次数一定多于他。所以我们只要判断关系就能判断往哪边找。代码:#include<bits/stdc++.h>using......
  • CSP/信奥赛C++语法基础刷题训练(9):洛谷P1035:[NOIP2002 普及组] 级数求和
    CSP/信奥赛C++语法基础刷题训练(9):洛谷P1035:[NOIP2002普及组]级数求和题目描述已知:Sn=1......
  • CSP/信奥赛C++语法基础刷题训练(10):洛谷P1307:[NOIP2011 普及组] 数字反转
    CSP/信奥赛C++语法基础刷题训练(10):洛谷P1307:[NOIP2011普及组]数字反转题目描述给定一个整数NNN,请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式,......
  • 洛谷 P2890 [USACO07OPEN] Cheapest Palindrome G 做题记录
    我不会区间dp。设\(f_{i,j}\)表示使得区间\([i,j]\)为回文串的最小操作代价,\(cost_{i,j}\)表示字母\(i\)删除/添加的耗费,那么显而易见的,我们有:\(f_{i,j}\to\min(f_{i,j-1}+\min(cost_{s_j,0},cost_{s_j,1}),f_{i+1,j}+\min(cost_{s_i,0},cost_{s_i,1}))\)。当\(s_i......