题目描述

给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节。
如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到。

输入

第一行一个正整数n (n<=500,000),表示S的长度。
第二行n个小写英文字母,表示字符串S。
第三行一个正整数q (q<=2,000,000),表示询问个数。
下面q行每行两个正整数a,b (1<=a<=b<=n),表示询问字符串S[a..b]的最短循环节长度。

输出

依次输出q行正整数,第i行的正整数对应第i个询问的答案。

样例输入

8
aaabcabc
3
1 3
3 8
4 8

样例输出

1
3
5


题解

Hash+分解质因数

考虑如何求出一个字符串的最短循环节?使用KMP求出next数组,n-next[n]即为最短循环节。

那么考虑本题,判断一个长度是否为循环节,只需要判断前后字符串是否相等即可,可以使用Hash解决。

因为循环节长度一定是字符串长度的约数,由于一个数的约数最多只有$2\sqrt n$个,因此可以枚举约数然后判断,时间复杂度$O(q\sqrt n)$

考虑优化这个过程:如果$i$是循环节,那么$ki\ (ki|len)$也一定是循环节。所以我们可以对于串长的每个质因子,求出它在最短循环节中的指数次数。具体实现即对于现有循环节,判断除以质因子后是否还是循环节,如果是则除,不是则不变。

而分解质因数是可以通过线性筛做到线性预处理$O(\log n)$查询的,故总时间复杂度为$O(n+q\log n)$。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 500010
using namespace std;
typedef unsigned long long ull;
ull base[N] , hash[N];
int lp[N] , prime[N] , tot , np[N];
char str[N];
bool judge(int l , int r , int len)
{
return hash[l + len - 1] - hash[l - 1] * base[len] == hash[r] - hash[r - len] * base[len];
}
int main()
{
int n , i , j , m , l , r , v , now;
scanf("%d%s%d" , &n , str + 1 , &m);
for(i = 2 ; i <= n ; i ++ )
{
if(!np[i]) lp[i] = i , prime[++tot] = i;
for(j = 1 ; j <= tot && i * prime[j] <= n ; j ++ )
{
np[i * prime[j]] = 1 , lp[i * prime[j]] = prime[j];
if(i % prime[j] == 0) break;
}
}
base[0] = 1;
for(i = 1 ; i <= n ; i ++ ) base[i] = base[i - 1] * 2333 , hash[i] = hash[i - 1] * 2333 + str[i];
while(m -- )
{
scanf("%d%d" , &l , &r) , now = v = r - l + 1;
while(v != 1)
{
if(judge(l , r , r - l + 1 - now / lp[v])) now /= lp[v];
v /= lp[v];
}
printf("%d\n" , now);
}
return 0;
}

最新文章

  1. 【Python②】python之首秀
  2. NGUI UIToggle
  3. C string.h 常用函数
  4. Connection for controluser as defined in your configuration failed.
  5. linux上静态库链接的有关问题
  6. redis 安装实战(10步完成安装)
  7. NOIP2010题解
  8. 框架学习之Spring(一IOC)----HelloWrod
  9. SVN使用规范
  10. Hadoop源码分析(3): Hadoop的运行痕迹
  11. NetSec2019 20165327 Exp6 信息搜集与漏洞扫描
  12. 【BZOJ2655】calc DP 数学 拉格朗日插值
  13. 通过 onclick = &quot;test()&quot;事件定义的事件 , 如何触发.
  14. php 安装 phpredis 扩展
  15. css揭秘
  16. 廖雪峰git教程学习笔记3
  17. 什么是Spark(四)运算过程中的黑科技
  18. Golang之实现(链表)
  19. 常见编码和编码头BOM
  20. c++ 中 毫秒级时间获取

热门文章

  1. UVA 11997 K Smallest Sums (多路归并)
  2. argsort argmax
  3. django 数据库中中文转化为韩语拼音
  4. Python 消息框的处理
  5. 类扩展Extension
  6. 微信小程序传值取值的几种方法
  7. c++ 函数指针应用,定义一个方法,传入两个参数和一个函数指针,并返回结果
  8. 好久没写了,总结一下lnux常用的命令(基础)
  9. read design into DC memory
  10. paper:synthesizable finite state machine design techniques using the new systemverilog 3.0 enhancements 之 standard verilog FSM conding styles(三段式)