二分+后缀数组
并查集怎么做?
二分长度,然后扫描一遍,如果lcp比值大,那么肯定能满足这个x,因为lcp比x大说明包含长x的lcp
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N = 40010; int n, top, k, tot, m; int a[N], sa[N], rank[N], temp[N], lcp[N], s[N]; bool cp(int i, int j) { if(rank[i] != rank[j]) return rank[i] < rank[j]; int ri = i + k <= n ? rank[i + k] : -1; int rj = j + k <= n ? rank[j + k] : -1; return ri < rj; } void Sa() { for(int i = 1; i <= n; ++i) { sa[i] = i; rank[i] = s[i]; } for(k = 1; k <= n; k <<= 1) { sort(sa + 1, sa + n + 1, cp); temp[sa[1]] = 1; for(int i = 2; i <= n; ++i) temp[sa[i]] = temp[sa[i - 1]] + (cp(sa[i - 1], sa[i])); for(int i = 1; i <= n; ++i) rank[i] = temp[i]; } } void Lcp() { for(int i = 1; i <= n; ++i) rank[sa[i]] = i; int h = 0; for(int i = 1; i <= n; ++i) { int j = sa[rank[i] - 1]; if(rank[i] <= 1) continue; if(h) --h; for(; i + h <= n && j + h <= n; ++h) if(s[i + h] != s[j + h]) break; lcp[rank[i] - 1] = h; } } bool C(int x) { int mn = 1 << 29, mx = 0; for(int i = 1; i < n; ++i) { if(lcp[i] >= x) { mx = max(mx, max(sa[i], sa[i + 1])); mn = min(mn, min(sa[i], sa[i + 1])); if(mx - mn > x) return true; } else { mn = 1 << 29; mx = 0; } } return false; } int main() { int T; while(scanf("%d", &n)) { if(n == 0) break; for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); for(int i = 2; i <= n; ++i) s[i - 1] = a[i] - a[i - 1] + 100; --n; Sa(); Lcp(); int l = 1, r = 20010, ans = 0; while(r - l > 1) { int mid = (l + r) >> 1; if(C(mid)) l = ans = mid; else r = mid; } if(ans < 4) puts("0"); else printf("%d ", ans + 1); } return 0; }