先放一下做这道题可能要用到的几个性质 :
_ 循环节一定是总长度的约数
_ 若字符串s有一个循环节k,则k * i也是s的循环节
_n是[l,r]这一段的循环节 的充要条件是 [l,r-n]和[l+n,r]相同(可以感性理解一下em)
知道这几点之后,就可以做这道题啦!୧(๑•̀⌄•́๑)૭
假设此时我们要处理一个长度为(len)的字符串(s), 当前找到了一个(s)的循环节(ans)
那么我们再继续找(ans)的循环节,如果能找到的话,那这个(ans)的循环节一定也是(s)的循环节的
这么一直找啊找,最后就可以找到最短循环节啦em
具体的操作流程:
首先将(ans)初值赋为(len)(因为最长的循环节长度一定是(len)), 枚举(len) 的质因数(假设此时枚举到了(x))
若(ans/x)是循环节,则将ans 更新成(ans/ x)
#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
const int N = 5e5 + 5;
const int Q = 2e6 + 5;
int n, q, cnt;
string sa;
int prime[N], is_prime[N];
ull h[N], power[N];
bool check(int len, int l, int r) {
ull x = h[r - len] - h[l - 1] * power[r - len - l + 1];
ull y = h[r] - h[l + len - 1] * power[r - len - l + 1];
return x == y;
}
inline int read() {
int x = 0; char c = getchar(); bool f = 1;
while(c < '0' || c > '9') { if(c == '-') f = !f; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return f ? x : -x;
}
int main() {
cin >> n >> sa;
power[0] = 1;
for(int i = 1; i <= n; i++) {
h[i] = h[i - 1] * 233 + sa[i - 1];
power[i] = power[i - 1] * 233;
}
q = read();
for(int i = 1; i <= q; i++) {
int l = read();
int r = read();
int len = r - l + 1;
int ans = len;
int x = 2;
while(len != 1 && x <= len) {
while(ans % x == 0 && check(ans / x, l, r)) ans /= x;
while(len % x == 0) len /= x;
x++;
}
printf("%d
", ans);
}
return 0;
}