POJ 3261 Milk Patterns

题目大意:

给N个数, 和一个正整数K, 求出在这串数中出现过至少K次的子串的最大长度, 这里对出现的字串计数时可以重叠.

 

简要分析:

二分答案M, 然后从左到右算一遍长为M的子串的哈希值, 丢到map里面进行计数, 时间复杂度O(NlogN).

 

代码实现:

View Code
 1 #include <cstdio>
2 #include <cstdlib>
3 #include <cstring>
4 #include <algorithm>
5 using namespace std;
6
7 typedef unsigned long long hash_t;
8 const int MAX_N = 20000, SEED = 99991;
9 int n, k, s[MAX_N];
10 hash_t mypow[MAX_N];
11
12 struct hash_map_t {
13 static const int MOD = 196613;
14 int cnt, begin[MOD], val[MAX_N], next[MAX_N];
15 hash_t end[MAX_N];
16 void clear() { cnt = 0, memset(begin, -1, sizeof(begin)); }
17 hash_map_t() { cnt = 0, memset(begin, -1, sizeof(begin)); }
18 int push(hash_t x) {
19 int s = x % MOD;
20 for (int now = begin[s]; now != -1; now = next[now])
21 if (end[now] == x) {
22 val[now] ++;
23 return val[now];
24 }
25 next[cnt] = begin[s];
26 begin[s] = cnt;
27 end[cnt] = x;
28 val[cnt ++] = 1;
29 return 1;
30 }
31 } cnt;
32
33 bool check(int len) {
34 cnt.clear();
35 hash_t t = 0ULL;
36 for (int i = 0; i < len; i ++) t = t * SEED + s[i];
37 cnt.push(t);
38 for (int i = 1; i < n - len + 1; i ++) {
39 t = (t - s[i - 1] * mypow[len - 1]) * SEED + s[i + len - 1];
40 if (cnt.push(t) >= k) return 1;
41 }
42 return 0;
43 }
44
45 int main() {
46 mypow[0] = 1ULL;
47 for (int i = 1; i < MAX_N; i ++) mypow[i] = mypow[i - 1] * SEED;
48 while (scanf("%d%d", &n, &k) != EOF) {
49 for (int i = 0; i < n; i ++) scanf("%d", &s[i]);
50 int lb = 0, rb = n;
51 while (lb + 1 < rb) {
52 int mid = (lb + rb) >> 1;
53 if (check(mid)) lb = mid;
54 else rb = mid;
55 }
56 printf("%d\n", lb);
57 }
58 return 0;
59 }
posted @ 2012-03-09 22:30  zcwwzdjn  阅读(176)  评论(0编辑  收藏  举报