BZOJ1717: [Usaco2006 Dec]Milk Patterns 产奶的模式
1717: [Usaco2006 Dec]Milk Patterns 产奶的模式
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1444 Solved: 784
[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
HINT
Source
【题解】
蓝书上的SA模板有误!!!!!!!
求height的时候, while(s[i + k] == s[j + k]) ++ k;一句,
应写作while(s[i + k] == s[j + k] && i + k < n && j + k < n) ++ k;
卡了我一下午。。。。。
据说是SA常用套路,分组+二分
二分答案x,判断LCP>=x次的字符串是否有k个。不难发现如果有一个height[i]小于x,那么后缀排好序后,所选两个字符串之间不能有i
(注:查询LCP的heigt是一个左开右闭区间,即查i,jLCP,rank[i] < rank[j],区间为(rank[i], rank[j]])
于是我们以height[i]小于x的i为分割线,将height分组,每次只能选组内的一个或多个
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 #include <cmath> 9 #define min(a, b) ((a) < (b) ? (a) : (b)) 10 #define max(a, b) ((a) > (b) ? (a) : (b)) 11 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a)) 12 template <class T> 13 inline void swap(T &a, T &b) 14 { 15 T tmp = a;a = b;b = tmp; 16 } 17 inline void read(int &x) 18 { 19 x = 0;char ch = getchar(), c = ch; 20 while(ch < '0' || ch > '9') c = ch, ch = getchar(); 21 while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); 22 if(c == '-') x = -x; 23 } 24 25 const int INF = 0x3f3f3f3f; 26 const int MAXN = 1000000 + 10; 27 28 struct SuffixArray 29 { 30 int s[MAXN], sa[MAXN], rank[MAXN], height[MAXN]; 31 int t[MAXN], t2[MAXN], c[MAXN]; 32 int n; 33 void clear(){n = 0;memset(sa, 0, sizeof(sa));} 34 35 void build_sa(int m) 36 { 37 int i, *x = t, *y = t2; 38 for(i = 0;i < m;++ i) c[i] = 0; 39 for(i = 0;i < n;++ i) ++ c[x[i] = s[i]]; 40 for(i = 1;i < m;++ i) c[i] += c[i - 1]; 41 for(i = n - 1;i >= 0;-- i) sa[--c[x[i]]] = i; 42 for(int k = 1;k <= n;k <<= 1) 43 { 44 int p = 0; 45 for(i = n - k;i < n;++ i) y[p ++] = i; 46 for(i = 0;i < n;++ i) if(sa[i] >= k) y[p ++] = sa[i] - k; 47 for(i = 0;i < m;++ i) c[i] = 0; 48 for(i = 0;i < n;++ i) ++ c[x[y[i]]]; 49 for(i = 1;i < m;++ i) c[i] += c[i - 1]; 50 for(i = n - 1;i >= 0;-- i) sa[--c[x[y[i]]]] = y[i]; 51 swap(x, y); 52 p = 1;x[sa[0]] = 0; 53 for(i = 1;i < n;++ i) 54 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p ++; 55 if(p >= n) break; 56 m = p; 57 } 58 } 59 60 void build_height() 61 { 62 int i,j,k = 0; 63 for(i = 0;i < n;++ i) rank[sa[i]] = i; 64 for(i = 0;i < n;++ i) 65 { 66 if(k) -- k; 67 j = sa[rank[i] - 1]; 68 while(s[i + k] == s[j + k] && i + k < n && j + k < n) ++ k; 69 height[rank[i]] = k; 70 } 71 } 72 }A; 73 74 int k,ma; 75 76 int check(int m) 77 { 78 int cnt = 0; 79 for(int i = 0;i < A.n;++ i) 80 if(A.height[i] >= m) 81 { 82 ++ cnt; 83 if(cnt + 1 == k) return 1; 84 } 85 else cnt = 0; 86 return 0; 87 } 88 89 int main() 90 { 91 read(A.n), read(k); 92 for(int i = 0;i < A.n;++ i) 93 read(A.s[i]), ma = max(ma, A.s[i]); 94 A.build_sa(ma + 1); 95 A.build_height(); 96 int l = 1, r = A.n, mid, ans = 0; 97 while(l <= r) 98 { 99 mid = (l + r) >> 1; 100 if(check(mid)) ans = mid, l = mid + 1; 101 else r = mid - 1; 102 } 103 printf("%d", ans); 104 return 0; 105 }