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

相关文章

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

Java 枚举的常用技巧汇总

《Java枚举的常用技巧汇总》在Java中,枚举类型是一种特殊的数据类型,允许定义一组固定的常量,默认情况下,toString方法返回枚举常量的名称,本文提供了一个完整的代码示例,展示了如何在Jav... 目录一、枚举的基本概念1. 什么是枚举?2. 基本枚举示例3. 枚举的优势二、枚举的高级用法1. 枚举

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

Rust中的Option枚举快速入门教程

《Rust中的Option枚举快速入门教程》Rust中的Option枚举用于表示可能不存在的值,提供了多种方法来处理这些值,避免了空指针异常,文章介绍了Option的定义、常见方法、使用场景以及注意事... 目录引言Option介绍Option的常见方法Option使用场景场景一:函数返回可能不存在的值场景

C#中字符串分割的多种方式

《C#中字符串分割的多种方式》在C#编程语言中,字符串处理是日常开发中不可或缺的一部分,字符串分割是处理文本数据时常用的操作,它允许我们将一个长字符串分解成多个子字符串,本文给大家介绍了C#中字符串分... 目录1. 使用 string.Split2. 使用正则表达式 (Regex.Split)3. 使用

JAVA中while循环的使用与注意事项

《JAVA中while循环的使用与注意事项》:本文主要介绍while循环在编程中的应用,包括其基本结构、语句示例、适用场景以及注意事项,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录while循环1. 什么是while循环2. while循环的语句3.while循环的适用场景以及优势4. 注意

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

Python中处理NaN值的技巧分享

《Python中处理NaN值的技巧分享》在数据科学和数据分析领域,NaN(NotaNumber)是一个常见的概念,它表示一个缺失或未定义的数值,在Python中,尤其是在使用pandas库处理数据时,... 目录NaN 值的来源和影响使用 pandas 的 isna()和 isnull()函数直接比较 Na

Oracle数据库执行计划的查看与分析技巧

《Oracle数据库执行计划的查看与分析技巧》在Oracle数据库中,执行计划能够帮助我们深入了解SQL语句在数据库内部的执行细节,进而优化查询性能、提升系统效率,执行计划是Oracle数据库优化器为... 目录一、什么是执行计划二、查看执行计划的方法(一)使用 EXPLAIN PLAN 命令(二)通过 S