题目描述 https://www.luogu.com.cn/problem/P3538
简要题意:给定字符串 $S$ 和 $m$,接下来有 $m$ 次询问,每次求 $S[l\cdots r]$ 的最短循环节长度,这里的循环节的定义为如果 $t$ 是 $S$ 的循环节,则 $S$ 由 $t$ 重复若干次得到
$n\le 5\times 10^5,m\le 10^6$
Solution 我们考虑每次询问暴力枚举约数 $d$,我们知道当 $n=5\times 10^5$ 时 $max_{i=1}^n\tau(i)=200$,这还算是能够接受的
那么我们如何判断 $S[l\cdots l+d-1]$ 是 $S[l\cdots r]$ 的循环节呢,注意到如果 $S[l\cdots r-d]$ 与 $S[l+d\cdots r]$ 相等的话,$S[l\cdots l+d-1]$ 一定是 $S[l\cdots r]$ 的循环节,这是个很经典的结论
判断相等可以使用字符串 $hash$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <iostream> #include <cstring> #include <vector> #include <algorithm> #define maxn 500010 #define ll long long #define uint unsigned int using namespace std ;struct Hash { const int base = 131 ; uint pow [maxn], h[maxn]; void init (char *s) { int l = strlen (s + 1 ); pow [0 ] = 1 ; for (int i = 1 ; i <= l; ++i) pow [i] = pow [i - 1 ] * base; for (int i = 1 ; i <= l; ++i) h[i] = s[i] + h[i - 1 ] * base; } uint get (int l, int r) { return h[r] - h[l - 1 ] * pow [r - l + 1 ]; } uint hash (char *s) { int l = strlen (s + 1 ); uint ans = 0 ; for (int i = 1 ; i <= l; ++i) ans = s[i] + ans * base; return ans; } } h; int n, m;char s[maxn];vector <int > d[maxn];int main () { ios::sync_with_stdio(false ); cin .tie(nullptr ); cout .tie(nullptr ); cin >> n >> s + 1 ; h.init(s); for (int i = 1 ; i <= n; ++i) for (int j = i; j <= n; j += i) d[j].push_back(i); cin >> m; for (int i = 1 ; i <= m; ++i) { int x, y; cin >> x >> y; for (auto t : d[y - x + 1 ]) if (h.get(x, y - t) == h.get(x + t, y)) { cout << t << "\n" ; break ; } } return 0 ; }