POI 2012 OKR - A Horrible Poem 题解

2024-02-12 09:40
文章标签 2012 题解 okr poi poem horrible

本文主要是介绍POI 2012 OKR - A Horrible Poem 题解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目传送门

题目大意: 有一个长度为 n n n的字符串,每次询问一个字串的最短循环节。

题解

最最暴力的做法:枚举长度 l e n len len,每次将该长度的字串与原串暴力匹配一遍。

然后考虑优化:

1.

显然 l e n len len 一定是 n n n 的因数,于是枚举 l e n len len 的时候只需要枚举 n n n 的因数即可。

2.

匹配可以用哈希来搞,但是如果将相邻的两节依次匹配的话还是很慢,最坏时间复杂度为 O ( n ) O(n) O(n),于是如何进一步优化呢?

仔细观察一下匹配过程:
在这里插入图片描述

每一次匹配都是跟自己右边的匹配,然后我们又知道,hash的匹配无论多长都是 O ( 1 ) O(1) O(1) 的,于是像这样子搞一搞——
在这里插入图片描述

将字符串复制一份,一个掐头,一个去尾,然后直接匹配,效果与两两匹配是一样的,因为现在上下对应的两个就是原来左右相邻的两个。

3.

part 1

经过尝试后,发现用 O ( n ) O(\sqrt n) O(n ) 的方法来枚举因数还是不够优秀的(卡了半天常也过不去,可能是我太蒟了qaq),于是发掘一下更加优秀的做法。

一个数可以写成 a 1 b 1 a 2 b 2 . . . a_1^{b_1}a_2^{b_2}... a1b1a2b2... 的形式,对于每个数,虽然因数可能很多,但是它的质因数个数实际少得可怜,并且每一个数的 a a a 数组和 b b b 数组都是可以预处理的,于是只需要枚举每一个质因数的指数就可以了。

但这种做法只是比 O ( n ) O(\sqrt n) O(n ) 的做法快那么一点,所以总的时间复杂度依然不乐观……

综上,枚举因数似乎不大好做,于是需要换一种做法。


part 2

有一个看似很废的性质:假如长度 x x x 是字符串的一个循环节,那么当 x ∗ k x*k xk 也是总长的一个因数时, x ∗ k x*k xk 也一定是一个循环节。

一开始觉得它很废是因为如果要得到 x ∗ k x*k xk 首先肯定要得到 x x x,但那我都有 x x x 了我还要 x ∗ k x*k xk 有鸟用?

但是换一个角度看这条性质,它其实等价于——假如长度 x x x 不是循环节,那么它的因数就都不是循环节。

于是根据这条性质,就得到了另一种做法,将 l e n len len 的质因子都找出来,假如 l e n / len/ len/某质因子 之后,得到的长度依然是一个循环节,那么 l e n len len 就除以这个因子,否则就不除,因为除了之后得到的那个因数不是循环节,根据上述性质,我们并不能用这个奇怪的因数得到答案。

4.

卡常qwq

最后附上代码,还有些没讲到的细节里面有:

#pragma GCC optimize(3)
#include <cstdio>
#include <cstring>
#define ull unsigned long long
#define jinzhi 315ull
#define mod 2147463647ull
#define R register
#define maxn 500010int n,m;
char s[maxn];
inline int ch(char x){return x-'a';};
ull hash[maxn],power[maxn];
inline ull get(int l,int r){return (hash[r]-hash[l-1]*power[r-l+2]%mod+mod)%mod;};
//滚动哈希求子串的哈希值
inline bool check(const int x,const int y,int blo){return get(x,y-blo)==get(x+blo,y);}
//看长度blo是不是x~y这个子串的循环节
inline char nc()
{static char buf[1000010],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}//读优
void read(int &x)
{x=0;char ch=nc();while(ch<'0'||ch>'9')ch=nc();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=nc();
}
bool v[maxn];
int prime[maxn],t=0;
void work()//线性筛素数
{for(int i=2;i<=maxn-10;i++){if(!v[i])prime[++t]=i;for(int j=1;j<=t;j++){if(prime[j]*i>maxn-10)break;v[prime[j]*i]=true;if(i%prime[j]==0)break;}}
}
int minfactor[maxn];
//每一个数的最小质因子,后面分解质因数时用到
void work2()//预处理minfactor
{for(int i=1;i<=t;i++){for(int j=1;j*prime[i]<=maxn-10;j++)if(!minfactor[prime[i]*j])minfactor[prime[i]*j]=prime[i];}
}
int a[maxn],st;int main()
{scanf("%d",&n);scanf("%s\n",s+1);work();work2();for(R int i=1;i<=n;++i)hash[i]=(hash[i-1]*jinzhi%mod+(ull)s[i])%mod;power[1]=1;for(R int i=2;i<=n;++i)power[i]=power[i-1]*jinzhi%mod;read(m);R int x,y;while(m--){read(x);read(y);int block(y-x+1);st=0;while(block!=1)a[++st]=minfactor[block],block/=minfactor[block];//用a存下将block分解质因数后的结果block=y-x+1;//记得还原blockfor(int i=1;i<=st;i++)if(check(x,y,block/a[i]))block/=a[i];printf("%d\n",block);}
}

这篇关于POI 2012 OKR - A Horrible Poem 题解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/702297

相关文章

java中使用POI生成Excel并导出过程

《java中使用POI生成Excel并导出过程》:本文主要介绍java中使用POI生成Excel并导出过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求说明及实现方式需求完成通用代码版本1版本2结果展示type参数为atype参数为b总结注:本文章中代码均为

Java利用poi实现word表格转excel

《Java利用poi实现word表格转excel》这篇文章主要为大家详细介绍了Java如何利用poi实现word表格转excel,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、每行对象类需要针对不同的表格进行对应的创建。package org.example.wordToEx

使用Apache POI在Java中实现Excel单元格的合并

《使用ApachePOI在Java中实现Excel单元格的合并》在日常工作中,Excel是一个不可或缺的工具,尤其是在处理大量数据时,本文将介绍如何使用ApachePOI库在Java中实现Excel... 目录工具类介绍工具类代码调用示例依赖配置总结在日常工作中,Excel 是一个不可或缺的工http://

Java实战之利用POI生成Excel图表

《Java实战之利用POI生成Excel图表》ApachePOI是Java生态中处理Office文档的核心工具,这篇文章主要为大家详细介绍了如何在Excel中创建折线图,柱状图,饼图等常见图表,需要的... 目录一、环境配置与依赖管理二、数据源准备与工作表构建三、图表生成核心步骤1. 折线图(Line Ch

Java使用POI-TL和JFreeChart动态生成Word报告

《Java使用POI-TL和JFreeChart动态生成Word报告》本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码... 目录前言一、需求背景二、方案分析三、 POI-TL + JFreeChart 实现3.1 Maven

SpringBoot使用Apache POI库读取Excel文件的操作详解

《SpringBoot使用ApachePOI库读取Excel文件的操作详解》在日常开发中,我们经常需要处理Excel文件中的数据,无论是从数据库导入数据、处理数据报表,还是批量生成数据,都可能会遇到... 目录项目背景依赖导入读取Excel模板的实现代码实现代码解析ExcelDemoInfoDTO 数据传输

java poi实现Excel多级表头导出方式(多级表头,复杂表头)

《javapoi实现Excel多级表头导出方式(多级表头,复杂表头)》文章介绍了使用javapoi库实现Excel多级表头导出的方法,通过主代码、合并单元格、设置表头单元格宽度、填充数据、web下载... 目录Java poi实现Excel多级表头导出(多级表头,复杂表头)上代码1.主代码2.合并单元格3.

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

C - Word Ladder题解

C - Word Ladder 题解 解题思路: 先输入两个字符串S 和t 然后在S和T中寻找有多少个字符不同的个数(也就是需要变换多少次) 开始替换时: tips: 字符串下标以0开始 我们定义两个变量a和b,用于记录当前遍历到的字符 首先是判断:如果这时a已经==b了,那么就跳过,不用管; 如果a大于b的话:那么我们就让s中的第i项替换成b,接着就直接输出S就行了。 这样