[模板]後綴自動機
阿新 • • 發佈:2019-03-05
tmp pan tdi 刪掉 cond sort 出現次數 自動機 區間
題面:
給一個字符串 \(S\) ,求出 \(S\) 的所有出現次數不為 \(1\) 的子串的出現次數乘上該子串長度的最大值
法一:SAM(由於本蒟蒻太菜現在還不會)
咕咕咕...
法二:SA
先後綴排序, 求出 \(Height\) 數組,然後弄好ST表,從小到大處理每一個前綴,統計完一個前綴的答案後,就刪掉它,然後再繼續操作左右兩個裂開的區間,代碼寫的很清楚,這裏不在贅述。
SA的做法還是挺巧妙的。
#include <set> #include <cmath> #include <cctype> #include <cstdio> #include <cstring> #include <iostream> #include <assert.h> #include <algorithm> using namespace std; #define fir first #define sec second #define pb push_back #define mp make_pair #define LL long long #define INF (0x3f3f3f3f) #define mem(a, b) memset(a, b, sizeof (a)) #define debug(...) fprintf(stderr, __VA_ARGS__) #define Debug(x) cout << #x << " = " << x << endl #define tralve(i, x) for (register int i = head[x]; i; i = nxt[i]) #define For(i, a, b) for (register int (i) = (a); (i) <= (b); ++ (i)) #define Forr(i, a, b) for (register int (i) = (a); (i) >= (b); -- (i)) #define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout) #define ____ debug("go\n") namespace io { static char buf[1<<21], *pos = buf, *end = buf; inline char getc() { return pos == end && (end = (pos = buf) + fread(buf, 1, 1<<21, stdin), pos == end) ? EOF : *pos ++; } inline int rint() { register int x = 0, f = 1;register char c; while (!isdigit(c = getc())) if (c == '-') f = -1; while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getc())); return x * f; } inline LL rLL() { register LL x = 0, f = 1; register char c; while (!isdigit(c = getc())) if (c == '-') f = -1; while (x = (x << 1ll) + (x << 3ll) + (c ^ 48), isdigit(c = getc())); return x * f; } inline void rstr(char *str) { while (isspace(*str = getc())); while (!isspace(*++str = getc())) if (*str == EOF) break; *str = '\0'; } template<typename T> inline bool chkmin(T &x, T y) { return x > y ? (x = y, 1) : 0; } template<typename T> inline bool chkmax(T &x, T y) { return x < y ? (x = y, 1) : 0; } } using namespace io; const int N = 1e6 + 2; namespace SA { char str[N]; int n, sa[N], rk[N], ht[N], M; void Rsort(int *buc, int *tp) { fill(buc, buc + 1 + M, 0); For (i, 1, n) buc[rk[i]] ++; For (i, 1, M) buc[i] += buc[i - 1]; Forr (i, n, 1) sa[ buc[ rk[ tp[i] ] ] -- ] = tp[i]; } void SuffixSort() { static int buc[N], tp[N]; M = 76; For (i, 1, n) rk[i] = str[i - 1] - '0', tp[i] = i; Rsort(buc, tp); for (register int len = 1, cnt = 0; cnt < n; len <<= 1, M = cnt) { cnt = 0; For (i, n - len + 1, n) tp[++cnt] = i; For (i, 1, n) if (sa[i] - len > 0) tp[++cnt] = sa[i] - len; Rsort(buc, tp); swap(rk, tp); rk[sa[1]] = cnt = 1; For (i, 2, n) rk[sa[i]] = (tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + len] == tp[sa[i - 1] + len] ? cnt : ++cnt); } } void getHt() { int len = 0; For (i, 1, n) { if (len) len --; int j = sa[rk[i] - 1]; while (str[j + len - 1] == str[i + len - 1]) len ++; ht[rk[i]] = len; } } #define pii pair<int, int> int Log[N]; pii st[N][22]; void STinit() { Log[0] = -1; For (i, 1, n) Log[i] = Log[i >> 1] + 1, st[i][0] = mp(ht[i], i); for (register int i = 1; n >> i; ++ i) for (register int j = 1; j + (1 << i) - 1 <= n; ++ j) st[j][i] = min(st[j][i - 1], st[j + (1 << i - 1)][i - 1]); } pii query(int l, int r) { int len = Log[r - l + 1]; return min(st[l][len], st[r - (1 << len) + 1][len]); } #undef pii } int ans = 0; void solve(int l, int r) { if (l > r) return; pair<int, int> tmp = SA::query(l, r); chkmax(ans, (r - l + 2) * tmp.fir); solve(l, tmp.sec - 1); solve(tmp.sec + 1, r); } int main() { #ifndef ONLINE_JUDGE file("SA"); #endif scanf("%s", SA::str); SA::n = strlen(SA::str); SA::SuffixSort(); SA::getHt(); SA::STinit(); solve(1, SA::n); cout << ans << endl; }
[模板]後綴自動機