HLG 1543 序列难题[后缀数组]
题意:
给出长度为n的数字序列,求重复出现次数不小于k的最长序列(连续)的长度。
例如序列 1 2 3 2 3 2 3 1,k=2,那么序列2 3 2 3重复出现了两次,长度为4。
分析:
二分枚举长度,如果在height数组中连续出现超过k次的话就满足。
View Code
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1000002; int s[maxn]; int sa[maxn],t[maxn],t2[maxn],c[maxn]; int N; void build_sa(int n,int m) { int i, *x=t, *y=t2; for (i=0; i<m; i++) c[i] = 0; for (i=0; i<n; i++) c[x[i] = s[i]]++; for (i=1; i<m; i++) c[i] += c[i-1]; for (i=n-1; i>=0; i--) sa[--c[x[i]]] = i; int p; for (int k=1; k<=n; k<<=1) { p = 0; for (i=n-k; i<n; i++) y[p++] = i; for (i=0; i<n; i++) if (sa[i] >= k) y[p++] = sa[i]-k; for (i=0; i<m; i++) c[i] = 0; for (i=0; i<n; i++) c[x[y[i]]]++; for (i=0; i<m; i++) c[i] += c[i-1]; for (i=n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i]; swap(x, y); p = 1; x[sa[0]] = 0; for (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 rank[maxn],height[maxn]; void getheight() { int i, j, k = 0; for (i=1; i<=N; i++) rank[sa[i]] = i; for (i=0; i<N; i++){ if (k) k--; int j = sa[rank[i]-1]; while (s[i+k] == s[j+k]) k++; height[rank[i]] = k; } } bool ok(int len, int k) { int i; int tot = 1; for (i=1; i<=N; i++){ if ( height[i] >= len){ tot++; if (tot >= k) return true; } else tot = 1; } return false; } void solve(int k) { int i, j; int l, r, mid, res; l = k; r = N; while (l <= r){ mid = (l+r)/2; if (ok(mid, k)){ res = mid; l = mid+1; } else r = mid-1; } printf("%d\n",res); } int main() { // freopen("in.in","r",stdin); int k, i; while (scanf("%d %d",&N,&k)!=EOF) { for (i=0; i<N; i++){ scanf("%d", &s[i]); } build_sa(N+1,20001);// N+1之后,sa下标就是从1开始了 getheight(); solve(k); } return 0; }