POJ-1743 Musial Theme(字尾陣列 + 二分)(男人八題)
阿新 • • 發佈:2020-07-22
題意:有N(1 <= N <= 20000)個音符的序列來表示一首樂曲,每個音符都是1...88範圍內的整數,現在要找一個重複的子串,它需要滿足如下條件:1.長度至少為5個音符。2.在樂曲中重複出現(就是出現過至少兩次)。(可能經過轉調,"轉調"的意思是主題序列中每個音符都被加上或者減去了同一個整數值)3.重複出現的同一主題不能有公共部分。
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <algorithm> using namespace std; const int N = 20005; const int inf = 0x3f3f3f3f; int a[N]; int p[N]; int n, k; int rk[N], tmp[N]; int sa[N], lcp[N]; bool compare_sa(int i, int j) { if (rk[i] != rk[j]) return rk[i] < rk[j]; else { int ri = i + k <= n ? rk[i + k] : -1; int rj = j + k <= n ? rk[j + k] : -1; return ri < rj; } } void construct_sa(int a[], int sa[]) { for (int i = 0; i <= n; ++i) { sa[i] = i; rk[i] = i < n ? a[i] : -1; } for (k = 1; k <= n; k *= 2) { sort(sa, sa + n + 1, compare_sa); tmp[sa[0]] = 0; for (int i = 1; i <= n; ++i) { tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0); } for (int i = 0; i <= n; ++i) { rk[i] = tmp[i]; } } } void construct_lcp(int a[], int sa[], int lcp[]) { for (int i = 0; i <= n; ++i) rk[sa[i]] = i; int h = 0; lcp[0] = 0; for (int i = 0; i < n; ++i) { int j = sa[rk[i] - 1]; if (h > 0) --h; for (; j + h < n && i + h < n; ++h) { if (a[j + h] != a[i + h]) break; } lcp[rk[i] - 1] = h; } } bool check(int mid) { int mx = -inf, mn = inf; for (int i = 0; i <= n; ++i) { if (lcp[i] >= mid) { mx = max(mx, max(sa[i], sa[i + 1])); mn = min(mn, min(sa[i], sa[i + 1])); if (mx - mn >= mid) return true; } else { mx = -inf; mn = inf; } } return false; } void init() { memset(sa, 0, sizeof sa); memset(lcp, 0, sizeof lcp); memset(rk, 0, sizeof rk); memset(tmp, 0, sizeof tmp); memset(p, 0, sizeof p); } int main() { while (scanf("%d", &n) != EOF, n) { init(); for (int i = 0; i < n; ++i) scanf("%d", &p[i]); for (int i = 0; i < n - 1; ++i) a[i] = p[i + 1] - p[i]; a[n] = 0; construct_sa(a, sa); construct_lcp(a, sa, lcp); int l = 0, r = n >> 1; while (l < r) { int mid = l + r + 1 >> 1; if (check(mid)) l = mid; else r = mid - 1; } if(l >= 4) printf("%d\n", l + 1); else { puts("0"); } } return 0; }