首页 > 其他分享 >题解 [POI2012] OKR-A Horrible Poem

题解 [POI2012] OKR-A Horrible Poem

时间:2023-08-07 10:55:59浏览次数:41  
标签:OKR POI2012 题解 while len 枚举 循环 long 长度

题目链接

询问循环节的“模板题”?

首先,有一个经典结论:若存在一长度为 \(len\) 的循环节,则 \(s[l \sim r-len]=s[l+len \sim r]\),简单来说就是利用移位,说明是否是循环节。

有了这个结论,再使用字符串哈希,我们就可以做到 \(O(1)\) 判断。

因为:字符串长度=循环节长度 \(\times\) 循环次数。
所以我们要么枚举循环节长度,要么枚举循环次数。两个都得是字符串长度的因数。

如果枚举循环节长度,考虑先预处理出所有长度的因数,时间为 \(O(n\log n)\),每次查询最坏的可能是 \(O(q \sqrt n )\),最坏情况下无法通过。

而循环节长度显然是不好优化的,因为如果长度为 \(1\) 的不行,不能说明长度为 \(2\) 的不行。而我们要求最短循环节,所以只能从小到大枚举,不利于优化。

考虑枚举循环次数(转化为求循环次数最大),若循环次数为 \(3\) 的不行,那么循环次数为 \(6,9,12...\) 的肯定也不行。

于是我们将长度质因数分解,对于每个质因数,如果除完之后可以,那么我们就除,用筛法记录下每个数字的最小质因子方便快速分解。

点击查看代码
#include<bits/stdc++.h>
using namespace std;

typedef unsigned long long ULL;
typedef long long LL;

LL read() {
    LL sum=0,flag=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') flag=-1; c=getchar();}
    while(c>='0'&&c<='9') {sum=sum*10+c-'0'; c=getchar();}
    return sum*flag;
}

const int N=5e5+10,M=5e5;
const LL MOD1=1e9+7,MOD2=998244353,base=13331;
int n,q;
LL p1[N],p2[N],h1[N],h2[N];
string s;
int f[N],fac[N];

void init() {
    for(int i=2;i<=M;i++) {
        if(f[i]) continue;
        for(int j=1;j*i<=M;j++) {
            if(!fac[i*j]) fac[i*j]=i;
            f[i*j]=1;
        }
    }
}

LL get1(int l,int r) {
    return ((h1[r]-h1[l-1]*p1[r-l+1])%MOD1+MOD1)%MOD1;
}

LL get2(int l,int r) {
    return ((h2[r]-h2[l-1]*p2[r-l+1])%MOD2+MOD2)%MOD2;
}

int main() {
    // freopen("a.in","r",stdin);
    // freopen("a.out","w",stdout);

    init();
    cin>>n>>s;
    s=" "+s;
    p1[0]=p2[0]=1;
    for(int i=1;i<=n;i++) {
        p1[i]=p1[i-1]*base%MOD1;
        p2[i]=p2[i-1]*base%MOD2;
        h1[i]=(h1[i-1]*base+s[i]-'a')%MOD1;
        h2[i]=(h2[i-1]*base+s[i]-'a')%MOD2;
    }
    cin>>q;
    while(q--) {
        int l,r; l=read(); r=read();
        int len=r-l+1,ans=r-l+1;
        while(len>1) {
            if(get1(l,r-ans/fac[len])==get1(l+ans/fac[len],r)) {
                ans/=fac[len];
            }
            len/=fac[len];
        }
        cout<<ans<<'\n';
    }
    
    return 0;
}
*/

标签:OKR,POI2012,题解,while,len,枚举,循环,long,长度
From: https://www.cnblogs.com/zhangyuzhe/p/17610822.html

相关文章

  • [国家集训队] Tree II 题解报告
    [国家集训队]TreeII一道·真·板子·题就是练习LCT懒标记的题目除了翻转标记以外还要维护乘法标记和加法标记注意加法标记和乘法标记的维护!!!加法标记因为splay的区间大小不是固定的,所以我们要维护size,并且子树的sum要加上size乘上标记其他的就只用直接加上即可voidpusha......
  • 题解 P8085 [COCI2011-2012#4] KRIPTOGRAM
    题目链接题目问的是相对位置是否一样,即若\(s\)的第\(1,2,3\)个字符串相等,\(t\)的第\(1,2,3\)个字符串也相等,则\(s=t\)。由于\(t\)的长度是固定的,所以我们使用哈希进行快速匹配。那么如何设计哈希函数则成为本题的难点。由于问相对位置,那么可以记\(val[i]\)表示......
  • 『MGOI』Simple Round I | B. 魔法照相馆 题解
    题目传送门一道模拟题。并不复杂的模拟题,也不需要用到贪心。我们可以创建一个数组来记录每个幕布是否被拉上,统计答案的时候,就看看这块幕布前面有多少个没拉上的,最后如果这块幕布拉上了,就重新放下来就行了。#include<bits/stdc++.h>#definelllonglong#defineINF1e9usi......
  • 【题解】Codeforces Round 890(CF1856)
    赛时过了A-E1,rk195可惜是E2傻逼了不会背包优化了,直接连普及组水平都不到了。A.TalesofaSort题目描述:给定长度为\(n\)的序列\(a\),每次操作为对于所有\(i\)将\(a_i\)变为\(\max(a_i-1,0)\),询问最少多少次操作之后可以让序列\(a\)单调不降。题目分析:唯一能改变......
  • 【题解】Luogu[P9504] 『MGOI』Simple Round I C. 魔法禁林
    Link这题我们发现如果直接去枚举生命和法力值显然是不行的,又看到说最小的生命值,不禁想到最短路,但是怎么跑?我们令经过一条边之前魔力值为\(k\),那么该边的边权为\(\lfloor\dfrac{w}{k}\rfloor\),于是我们讲题目转化为了边权为\(\lfloor\dfrac{w}{k}\rfloor\)时\(s\)到\(t\)......
  • [ABC310] D~F 题解
    [ABC310]D~F题解D-PeacefulTeams暴力搜索,搜索每个人在的队伍,为了去重,在一个人第一次加入新的队伍之后跳出。bitset<N>st;voiddfs(intu){for(inti=1;i<=m;i++)if(pos[a[i]]&&pos[b[i]]&&pos[a[i]]==pos[b[i]])return;if(u>n)......
  • C++动态规划经典试题解析之打家劫舍系列
    1.前言力扣上有几道与打家劫舍相关的题目,算是学习动态规划时常被提及的经典试题,很有代表性,常在因内大大小小的社区内看到众人对此类问题的讨论。学习最好的方式便是归纳总结、借鉴消化,基于这个目的,本文对此类问题也做了讲解,在一些优秀思想的基础上添加了个人观点。闲话少说,进入......
  • P9499 「RiOI-2」change 题解--zhengjun
    思维妙妙题。赛时的错误做法:找到每个点往后进位变优的位置,最多\(O(\log)\)个;然后从前往后能变优就变优,往后贪心进位。hack数据:0133510021022输出:100这样子由于\(1\)到\(2\)不优,而\(1\)到\(3\)个数不够,所以导致无法进位到\(3\)。所以加强一下......
  • CentOS8安装Docker报错问题解决
    问题描述CentOS版本:8.5.2111。#cat/etc/redhat-releaseCentOSLinuxrelease8.5.2111安装准备:#安装所需软件包sudoyuminstall-yyum-utilsdevice-mapper-persistent-datalvm2#设置docker仓库:推荐阿里云sudoyum-config-manager--add-repohttp://mirrors.al......
  • Codeforces Round 890 (Div. 2) supported by Constructor Institute 题解
    A.TalesofaSort关键就是找逆序对记一组逆序对下标为\(l,r\),则求出最大的\(a_l\)即可B.GoodArrays记要构造的GoodArray为\(b\)前置:\(\forall1\lei\len,b_i=1\)然后\(O(n)\)扫一遍看一下有没有重复,有重复就\(b_i\leftarrowb_i+1\)扫完之后,记\(sum=\sum_......