A Horrible Poem (HYSBZ - 2795,字符串哈希 + 枚举最小循环节小技巧~)

本文主要是介绍A Horrible Poem (HYSBZ - 2795,字符串哈希 + 枚举最小循环节小技巧~),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.题目链接:

HYSBZ-2795

二.题目大意:

给一个长度为 n 的字符串,q 次询问,每次问 s[l...r] 的最小循环节.

三.分析:

技巧一:字符串 s[l, r] 具有循环节 k 等价于 s[l, r - k] == s[l + k, r].

技巧二:线性筛中预处理出每个数的最小质因子,可 O(logn) 进行质因数分解. 

技巧三:字符串的最小循环节可通过对字符串长度的每个质因子通过试除法求解.

之前找最小循环节的时候我都是去枚举字符串长度的约数,逐一 check,时间复杂度 O(\sqrt n)

考虑另一种方式,设 n 为字符串长度,ans 为最小循环节长度。

ans 的初始值不妨设为 n,即字符串自身是一个循环节.

对 n 进行质因子分解得到 n = p_1^{c_1}p_2^{c_2}...p_k^{c_k}

那么去检查 \frac{n}{p_1} 是否为循环节

若是,再去检查 \frac{n}{p_1^ 2} 是否为循环节 

否则,再去检查 \frac{n}{p_2} 是否为循环节.

四.代码实现:

#include <bits/stdc++.h>
using namespace std;typedef long long ll;
typedef unsigned long long ull;const int M = (int)5e5;
const int inf = 0x3f3f3f3f;
const ll mod = (ll)19890907;
const ull base = 131;char s[M + 5];
ull p[M + 5];
ull f[M + 5];bool is_prime[M + 5];
int prime[M + 5], cnt;
int v[M + 5];//最小质因子void init()
{memset(is_prime, 1, sizeof(is_prime));is_prime[0] = is_prime[1] = 0;for(int i = 2; i <= M; ++i){if(is_prime[i]){prime[++cnt] = i;v[i] = i;}for(int j = 1; j <= cnt && i * prime[j] <= M; ++j){is_prime[i * prime[j]] = 0;v[i * prime[j]] = prime[j];if(i % prime[j] == 0){break;}}}
}ull cal(int l, int r)
{return f[r] - f[l - 1] * p[r - l + 1];
}bool check(int l, int r, int k)
{return cal(l, r - k) == cal(l + k, r);
}int main()
{init();int n; scanf("%d", &n);scanf("%s", s + 1);p[0] = 1; for(int i = 1; i <= n; ++i) p[i] = p[i - 1] * base;f[0] = 1; for(int i = 1; i <= n; ++i) f[i] = f[i - 1] * base + s[i] - 'a' + 1;int q; scanf("%d", &q);while(q--){int l, r; scanf("%d %d", &l, &r);int len = r - l + 1, ans = r - l + 1;while(len != 1){int t = v[len];while(len % t == 0) len /= t;while(ans % t == 0 && check(l, r, ans / t)) ans /= t;}printf("%d\n", ans);}return 0;
}

 

这篇关于A Horrible Poem (HYSBZ - 2795,字符串哈希 + 枚举最小循环节小技巧~)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D

poj 1734 (floyd求最小环并打印路径)

题意: 求图中的一个最小环,并打印路径。 解析: ans 保存最小环长度。 一直wa,最后终于找到原因,inf开太大爆掉了。。。 虽然0x3f3f3f3f用memset好用,但是还是有局限性。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#incl

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d