ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

A Horrible Poem

2021-01-10 14:02:50  阅读:265  来源: 互联网

标签:子串 Poem const int 循环 Horrible 长度 质因数


A Horrible Poem

题目:

给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节
n≤500 000 表示S的长度。
q≤2 000 000 表示询问次数。

code:

/*
  Time: 1.10
  Worker: Blank_space
  Source: #10038. 「一本通 2.1 练习 4」A Horrible Poem
*/
/*---------------------------------------------------*/
#include<cstdio>
using namespace std;
/*---------------------------------------------------*/
const int base = 60;
const int A = 1e4 + 7;
const int B = 1e5 + 7;
const int C = 1e6 + 7;
const int D = 1e7 + 7;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
/*---------------------------------------------------*/
long long n, q, h[B << 3], pow[B << 3], prim[B << 3], cnt, c[B << 3], ans;
bool p, vis[B << 3];
char s[B << 3];
/*---------------------------------------------------*/
int read()
{
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
void pair()
{
	for(int i = 2; i <= n; i++)	if(!vis[i])
		for(int j = 1; j * i <= n; j++)
			if(!vis[i * j]) vis[i * j] = 1, prim[i * j] = i;
}
bool check(int l, int r, int x)
{
	if((h[r - x] - h[l - 1] * pow[r - l - x + 1] % mod + mod) % mod != (h[r] - h[l + x - 1] * pow[r - l - x + 1] % mod + mod) % mod) return 0;
	return 1;
}
/*---------------------------------------------------*/
int main()
{
//	freopen("okr2.in", "r", stdin);
//	freopen("", "w", stdout);
	
	n = read(); scanf("%s", s + 1); q = read(); pow[0] = 1; pair();
	for(int i = 1; i <= n; i++) pow[i] = pow[i - 1] * base % mod, h[i] = (h[i - 1] * base % mod + s[i] - 96) % mod;
	for(int i = 1; i <= q; i++)
	{
		int l = read(), r = read();
		int len = ans = r - l + 1; p = 0;
		while(len > 1)
		{
			int j = ans / prim[len]; len /= prim[len];
			if(check(l, r, j)) ans = j;
		}
		printf("%lld\n", ans);
	}
	
//	fclose(stdin);
//	fclose(stdout);
}

思路:

首先 第一个想法是暴力枚举

对于每一个区间 枚举一个子串看是否为循环节 判断的时候我们可以采用哈希 循环枚举每一个长度的子串

很明显 时间复杂度起飞了

考虑优化

能够构成区间循环节的子串的长度一定能被整个区间的长度整除 可以省去不必要的判断

判断的过程不需要循环比较整个串 如果一个子串是循环节 很显然的 其必然是从区间左端开始 且满足 \(s_{(l, r - x)} == s_{(l + x, r)}\)

这样我们将每一次的判断优化为了 \(O(1)\)

确实多过了几个点 到现在已经有六十分了(其实我自己写的代码参考题解之前也只有六十分)

最后一个强力的优化

线筛:可能被选出的循环节的长度一定是长度的质因数

正确性:

循环节的长度若不是区间长度的质因数
若其是质因数的倍数 则一定能由选出的质因数构成
否则其必然无法被整个区间的长度整除

所以我们可以直接预处理出长度的质因数
直接枚举质因数 判断即可

标签:子串,Poem,const,int,循环,Horrible,长度,质因数
来源: https://www.cnblogs.com/blank-space-/p/14258214.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有