http://acm.hdu.edu.cn/showproblem.php?pid=5558
对于每个后缀suffix(i),想要在前面i - 1个suffix中找到一个pos,使得LCP最大。这样做O(n^2)
考虑到对于每一个suffix(i),最长的LCP肯定在和他排名相近的地方取得。
按排名大小顺序枚举位置,按位置维护一个递增的单调栈,对于每一个进栈的元素,要算一算栈内元素和他的LCP最大是多少。
如果不需要输出最小的下标,最大的直接是LCP(suffix(st[top]), suffix(st[top - 1]))就是相邻的两个。
但是要求最小的下标,这样的话需要对整个栈进行一个遍历,找到下标最小的并且长度最大的。整个栈与新进来的栈顶元素的LCP存在单调性,单调递增,所以可以二分。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <string> #include <stack> #include <map> #include <set> #include <bitset> #define X first #define Y second #define clr(u,v); memset(u,v,sizeof(u)); #define in() freopen("data.txt","r",stdin); #define out() freopen("ans","w",stdout); #define Clear(Q); while (!Q.empty()) Q.pop(); #define pb push_back #define inf (0x3f3f3f3f) using namespace std; typedef long long ll; typedef pair<int, int> pii; const int INF = 0x3f3f3f3f; const int maxn = 100000 + 2; int sa[maxn], x[maxn], y[maxn], book[maxn]; bool cmp(int r[], int a, int b, int len) { return r[a] == r[b] && r[a + len] == r[b + len]; } void da(char str[], int sa[], int lenstr, int mx) { int *fir = x, *sec = y, *ToChange; for (int i = 0; i <= mx; ++i) book[i] = 0; for (int i = 1; i <= lenstr; ++i) { fir[i] = str[i]; book[str[i]]++; } for (int i = 1; i <= mx; ++i) book[i] += book[i - 1]; for (int i = lenstr; i >= 1; --i) sa[book[fir[i]]--] = i; for (int j = 1, p = 1; p <= lenstr; j <<= 1, mx = p) { p = 0; for (int i = lenstr - j + 1; i <= lenstr; ++i) sec[++p] = i; for (int i = 1; i <= lenstr; ++i) { if (sa[i] > j) sec[++p] = sa[i] - j; } for (int i = 0; i <= mx; ++i) book[i] = 0; for (int i = 1; i <= lenstr; ++i) book[fir[sec[i]]]++; for (int i = 1; i <= mx; ++i) book[i] += book[i - 1]; for (int i = lenstr; i >= 1; --i) sa[book[fir[sec[i]]]--] = sec[i]; // ToChange = fir, fir = sec, sec = ToChange; swap(fir, sec); fir[sa[1]] = 0; p = 2; for (int i = 2; i <= lenstr; ++i) { fir[sa[i]] = cmp(sec, sa[i - 1], sa[i], j) ? p - 1 : p++; } } } int height[maxn], RANK[maxn]; void calcHight(char str[], int sa[], int lenstr) { for (int i = 1; i <= lenstr; ++i) RANK[sa[i]] = i; int k = 0; for (int i = 1; i <= lenstr - 1; ++i) { k -= k > 0; int j = sa[RANK[i] - 1]; while (str[j + k] == str[i + k]) ++k; height[RANK[i]] = k; } } char str[maxn]; int dp[maxn][19]; vector<int> fuck[26]; const int need = 18; void init_RMQ(int n, int a[]) { for (int i = 1; i <= n; ++i) { dp[i][0] = a[i]; } for (int j = 1; j < need; ++j) { for (int i = 1; i + (1 << j) - 1 <= n; ++i) { dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); } } } int ask(int be, int en) { if (be > en) swap(be, en); be++; int k = (int)log2(en - be + 1); return min(dp[be][k], dp[en - (1 << k) + 1][k]); } int f; int st[maxn], top; int t[maxn]; int ans[maxn], id[maxn]; bool check(int pos, int len) { int res = ask(RANK[st[pos]], RANK[st[top]]); return res == len; } void work() { memset(ans, 0, sizeof ans); memset(id, 0x3f, sizeof id); scanf("%s", str + 1); int lenstr = strlen(str + 1); str[lenstr + 1] = ‘$‘; str[lenstr + 2] = ‘\0‘; da(str, sa, lenstr + 1, 128); calcHight(str, sa, lenstr + 1); // for (int i = 1; i <= lenstr + 1; ++i) { // printf("%d ", sa[i]); // } // printf("\n"); init_RMQ(lenstr + 1, height); printf("Case #%d:\n", ++f); top = 0; for (int i = 2; i <= lenstr + 1; ++i) { while (top >= 1 && sa[i] < st[top]) { top--; } st[++top] = sa[i]; if (top >= 2) { int tlen = ask(RANK[st[top]], RANK[st[top - 1]]); ans[st[top]] = tlen; id[st[top]] = st[top - 1]; int be = 1, en = top - 2; while (be <= en) { int mid = (be + en) >> 1; if (check(mid, tlen)) en = mid - 1; else be = mid + 1; } id[st[top]] = st[be]; } } // for (int i = 1; i <= lenstr; ++i) { // printf("%d ", ans[i]); // } // printf("\n"); top = 0; for (int i = lenstr + 1; i >= 2; --i) { while (top >= 1 && sa[i] < st[top]) { top--; } st[++top] = sa[i]; if (top >= 2) { int tlen = ask(RANK[st[top]], RANK[st[top - 1]]); if (ans[st[top]] < tlen) { ans[st[top]] = tlen; id[st[top]] = st[top - 1]; } else if (ans[st[top]] == tlen && id[st[top]] > st[top - 1]) { id[st[top]] = st[top - 1]; } else if (ans[st[top]] > tlen) continue; // 太小了 int be = 1, en = top - 2; while (be <= en) { int mid = (be + en) >> 1; if (check(mid, tlen)) en = mid - 1; else be = mid + 1; } if (check(be, tlen)) id[st[top]] = min(id[st[top]], st[be]); } } // for (int i = 1; i <= lenstr; ++i) { // printf("%d ", ans[i]); // } // printf("\n"); for (int i = 1; i <= lenstr;) { if (ans[i] == 0) { printf("%d %d\n", -1, str[i]); i++; } else { printf("%d %d\n", ans[i], id[i] - 1); i += ans[i]; } } } int main() { #ifdef local in(); #else #endif // printf("%d\n", 1 << 17); int t; scanf("%d", &t); while (t--) work(); return 0; }
HUID 5558 Alice's Classified Message 后缀数组+单调栈+二分
时间: 2024-10-10 21:52:34