【POJ 2406】Power Strings 连续重复子串
看的《后缀数组——处理字符串的有力工具》这篇论文,在那里这道题是用后缀数组实现的,复杂度为$O(nlogn)$,很明显长度为$2×10^6$的数据会TLE,所以必需得用复杂度为$O(n)$的KMP算法。第一次写KMP,我好弱啊QAQ
KMP:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 2000003; char s[N]; int p[N], j, n, i; int main() { while (scanf("%s", s + 1), s[1] != '.') { j = 0; n =strlen(s + 1); p[1] = 0; for(i = 2; i <= n; ++i) { while (j && s[j + 1] != s[i]) j = p[j]; if (s[j + 1] == s[i]) ++j; p[i] = j; } printf("%d\n", n % (n - p[n]) == 0 ? n / (n - p[n]) : 1); } return 0; }
TLE的后缀数组做法:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 2000003; int t1[N], t2[N], c[N]; void st(int *x, int *y, int *sa, int n, int m) { int i; for(i = 0; i < m; ++i) c[i] = 0; for(i = 0; i < n; ++i) ++c[x[y[i]]]; for(i = 1; i < m; ++i) c[i] += c[i - 1]; for(i = n - 1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i]; } void mkhz(int *a, int *sa, int n, int m) { int i, j, p, *x = t1, *y = t2, *t; for(i = 0; i < n; ++i) x[i] = a[i], y[i] = i; st(x, y, sa, n, m); for(j = 1, p = 1; p < n; j <<= 1, m = p) { for(i = n - j, p = 0; i < n; ++i) y[p++] = i; for(i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j; st(x, y, sa, n, m); for(t = x, x = y, y = t, x[sa[0]] = 0, p = 1, i = 1; i < n; ++i) x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + j] == y[sa[i - 1] + j] ? p - 1 : p++; } } void mkh(int *r, int *sa, int *rank, int *h, int n) { int k = 0, i, j; for(i = 1; i <= n; ++i) rank[sa[i]] = i; for(i = 1; i <= n; h[rank[i++]] = k) for(k ? --k : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; ++k); } char s[N]; int a[N], sa[N], rank[N], h[N], n, minn[N]; void mkmin() { int pos = rank[1]; minn[pos] = h[pos]; for(int i = pos; i > 1; --i) minn[i - 1] = min(minn[i], h[i]); for(int i = pos + 1; i <= n; ++i) minn[i] = min(minn[i - 1], h[i]); } void Qhz() { int sq = sqrt((double)n); for(int i = 1; i <= sq; ++i) if (n % i == 0 && minn[rank[1 + i]] == n - i) {printf("%d\n", n / i); return;} puts("1"); } int main() { while (scanf("%s", s + 1), s[1] != '.') { n = strlen(s + 1); for(int i = 1; i <= n; ++i) a[i] = s[i]; mkhz(a, sa, n + 1, 256); mkh(a, sa, rank, h, n); mkmin(); Qhz(); } return 0; }
呜呜呜~
NOI 2017 Bless All