HDU 5558 Alice's Classified Message——字尾陣列+set+二分+rmq
阿新 • • 發佈:2018-11-16
15合肥簽到題,不會後綴自動機只能用字尾陣列來湊了
我們要完成的工作是對s的每一個字尾suf[i],找以j(0<=j<i)為起點的一個子串,使得這個子串與suf[i]的公共字首儘量長
其實字尾陣列的做法挺明顯的,就是對於一個字尾suf[i],首先將它前面的字尾的rank值用set儲存,然後拿rank[i]在set裡二分找兩個與rank[i]最接近的rank,最大匹配一定在這兩個rank之中,之後用rmq求一下兩個區間的區間最小值得到兩個匹配長度,取個最大值就行,有了這些其餘的自己湊一湊就行了
.
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; const int INF = 0x3f3f3f3f; char s[maxn]; int sa[maxn], t[maxn], t2[maxn], c[maxn], n; void build_sa(int m) { int i, *x = t, *y = t2; for (int i = 0; i < m; i++) c[i] = 0; for (int i = 0; i < n; i++) c[x[i] = s[i]]++; for (int i = 1; i < m; i++) c[i] += c[i-1]; for (int i = n-1; i >= 0; i--) sa[--c[x[i]]] = i; for (int k = 1; k <= n; k <<= 1) { int p = 0; for (int i = n-k; i < n; i++) y[p++] = i; for (int i = 0; i < n; i++) if (sa[i] >= k) y[p++] = sa[i]-k; for (int i = 0; i < m; i++) c[i] = 0; for (int i = 0; i < n; i++) c[x[y[i]]]++; for (int i = 0; i < m; i++) c[i] += c[i-1]; for (int i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; swap(x, y); p = 1; x[sa[0]] = 0; for (int i = 1; i < n; i++){ x[sa[i]] = y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; } if (p >= n) break; m = p; } } int ran[maxn], height[maxn]; void getHeight() { int k = 0; for (int i = 0; i < n; i++) ran[sa[i]] = i; for (int i = 0; i < n; i++) { if (k) k--; int j = sa[ran[i]-1]; while (s[i+k] == s[j+k]) k++; height[ran[i]] = k; } } int dp[20][maxn]; void build_rmq() { for (int i = 0; i < 20; i++) { for (int j = 0; j < n; j++) { dp[i][j] = 0; } } for (int i = 2; i <= n; i++) dp[1][i-1] = height[i]; int len = (int)log2(n); for (int i = 2; i <= len; i++) { for (int j = 1; j + (1<<i)-1 <= n; j++) { dp[i][j] = min(height[j+(1<<(i-1))], min(dp[i-1][j], dp[i-1][j+(1<<(i-1))])); } } } int query_rmq(int l, int r) { int x = (int)log2(r-l+1); return min(dp[x][l], dp[x][r-(1<<x)+1]); } set<int> se; set<int>::iterator it1, it2; int T; int main() { scanf("%d", &T); for (int ks = 1; ks <= T; ks++) { scanf("%s", s); n = strlen(s); s[n] = '#'; n++; build_sa(128); getHeight(); n--; build_rmq(); int pos = 0; se.clear(); se.insert(-INF); se.insert(INF); printf("Case #%d:\n", ks); while (pos < n) { int k = 0, t = 0; it1 = it2 = se.upper_bound(ran[pos]); it1--; while (*it1 != -INF) { int x = query_rmq(*it1, ran[pos]); if (x < k || x == 0) break; if (x > k || (x == k && sa[*it1] < t)) { k = x; t = sa[*it1]; } it1--; } while (*it2 != INF) { int x = query_rmq(ran[pos], *it2); if (x < k || x == 0) break; if (x > k || (x == k && sa[*it2] < t)) { k = x; t = sa[*it2]; } it2++; } int old = pos; if (k == 0) { printf("%d %d\n", -1, (int)s[pos]); pos++; } else { printf("%d %d\n", k, t); pos += k; } for (int i = old; i < pos; i++) se.insert(ran[i]); } } return 0; }