[BZOJ1717][Usaco2006 Dec]Milk Patterns 产奶的模式
1717: [Usaco2006 Dec]Milk Patterns 产奶的模式
Time Limit: 5 Sec Memory Limit: 64 MB Submit: 1297 Solved: 705 [Submit][Status][Discuss]Description
农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。
Input
* Line 1: 两个整数 N,K。
* Lines 2..N+1: 每行一个整数表示当天的质量值。
Output
* Line 1: 一个整数:N天中最长的出现了至少K次的模式的长度
Sample Input
8 2
1
2
3
2
3
2
3
1
1
2
3
2
3
2
3
1
Sample Output
4
求出后缀数组以及height数组,二分答案,如果有连续$k-1$个的height>=mid则可行
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 20000 + 10; int n, m, k, s[maxn]; int *p[maxn], cnt, last; class cmp1{ public: bool operator () (int *a, int *b){ return *a < *b; } }; int tax[maxn], tp[maxn], sa[maxn], rank[maxn], height[maxn]; inline bool cmp(int *r, int x, int y, int l){ return r[x] == r[y] && r[x + l] == r[y + l]; } inline void rsort(){ for(int i = 0; i <= m; i++) tax[i] = 0; for(int i = 1; i <= n; i++) tax[rank[tp[i]]]++; for(int i = 1; i <= m; i++) tax[i] += tax[i - 1]; for(int i = n; i; i--) sa[tax[rank[tp[i]]]--] = tp[i]; } void suffix(){ for(int i = 1; i <= n; i++){ rank[i] = s[i]; tp[i] = i; } m = n; rsort(); for(int p, w = 1; w < n; w <<= 1, m = p){ p = 0; for(int i = n - w + 1; i <= n; i++) tp[++p] = i; for(int i = 1; i <= n; i++) if(sa[i] > w) tp[++p] = sa[i] - w; rsort(); swap(rank, tp); p = rank[sa[1]] = 1; for(int i = 2; i <= n; i++) rank[sa[i]] = cmp(tp, sa[i - 1], sa[i], w) ? p : ++p; } for(int i = 1, j, k = 0; i <= n; height[rank[i++]] = k) for(k ? k-- : 0, j = sa[rank[i] - 1]; s[i + k] == s[j + k]; k++); } inline bool Judge(int mid){ int tot = 0; for(int i = 1; i <= n; i++) if(height[i] >= mid){ tot++; if(tot == k - 1) return true; } else tot = 0; return false; } int main(){ scanf("%d %d", &n, &k); for(int i = 1; i <= n; i++) scanf("%d", p[i] = s + i); sort(p + 1, p + n + 1, cmp1()); last = *p[1]; *p[1] = cnt = 1; for(int i = 2; i <= n; i++){ if(*p[i] != last) cnt++; last = *p[i]; *p[i] = cnt; } suffix(); int l = 1, r = n, mid, ans; while(l <= r){ mid = l + r >> 1; if(Judge(mid)){ ans = mid; l = mid + 1; } else r = mid - 1; } printf("%d\n", ans); return 0; }