奥赛一本通 1460 A Horrible Poem
1460 A Horrible Poem
题目大意
给定一个字符串,多次询问某个子串的最短循环节。
知识要点
素数筛法、字符串哈希
解题思路
显然循环节的长度必然是这个子串长度的约数,先利用筛法求出每个数的最小质因数,然后每次尝试在总长度中除以最小质因数,要检查某个长度是否为循环周期可以使用字符串哈希。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N = 500005;
int prime[N], fact[N]; //最小质因子
int screen(int n) { //欧拉筛
int cnt = 0;
for(int i = 2; i <= n; i++) {
if(!fact[i]) prime[cnt++] = fact[i] = i;
for(int j = 0; j < cnt && i * prime[j] <= n; j++) {
fact[i * prime[j]] = prime[j];
if(i % prime[j] == 0) break;
}
}
return cnt;
}
char s[N];
int ha[N], pw[N]; //hash值使用自然溢出
int Hash(int l, int r) {
return ha[r] - ha[l - 1] * pw[r - l + 1];
}
int main() {
int n, q, l, r;
scanf("%d%s%d", &n, s + 1, &q);
screen(n);
pw[0] = 1;
for(int i = 1; i <= n; i++)
ha[i] = ha[i - 1] * 233 + s[i], pw[i] = pw[i - 1] * 233;
while(q--) {
int l, r, m, len, ans;
scanf("%d%d", &l, &r);
m = ans = r - l + 1;
while(m > 1) { //分解质因数
len = ans / fact[m], m /= fact[m]; //尝试缩短循环周期
if(Hash(l + len, r) == Hash(l, r - len)) ans = len;
}
printf("%d\n", ans);
}
return 0;
}

浙公网安备 33010602011771号