POJ 3261 (后缀数组 二分) Milk Patterns

这道题和UVa 12206一样,求至少重复出现k次的最长字串。

首先还是二分最长字串的长度len,然后以len为边界对height数组分段,如果有一段包含超过k个后缀则符合要求。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 const int maxn = 20000 + 10;
 7 const int maxm = 1000000 + 10;
 8
 9 int s[maxn];
10 int sa[maxn], height[maxn], rank[maxn];
11 int t[maxn], t2[maxn], c[maxm];
12 int n, k;
13
14 void build_sa(int m)
15 {
16     int i, *x = t, *y = t2;
17     for(i = 0; i < m; i++) c[i] = 0;
18     for(i = 0; i < n; i++) c[x[i] = s[i]]++;
19     for(i = 1; i < m; i++) c[i] += c[i - 1];
20     for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
21     for(int k = 1; k <= n; k <<= 1)
22     {
23         int p = 0;
24         for(i = n - k; i < n; i++) y[p++] = i;
25         for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
26         for(i = 0; i < m; i++) c[i] = 0;
27         for(i = 0; i < n; i++) c[x[y[i]]]++;
28         for(i = 1; i < m; i++) c[i] += c[i - 1];
29         for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
30         swap(x, y);
31         p = 1; x[sa[0]] = 0;
32         for(i = 1; i < n; i++)
33             x[sa[i]] = y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? p - 1 : p++;
34         if(p >= n) break;
35         m = p;
36     }
37 }
38
39 void build_height()
40 {
41     int i, j, k = 0;
42     for(i = 0; i < n; i++) rank[sa[i]] = i;
43     for(i = 0; i < n; i++)
44     {
45         if(k) k--;
46         j = sa[rank[i] - 1];
47         while(s[i + k] == s[j + k]) k++;
48         height[rank[i]] = k;
49     }
50 }
51
52 bool ok(int len)
53 {
54     int cnt = 0;
55     for(int i = 0; i < n; i++)
56     {
57         if(i == 0 || height[i] < len) cnt = 0;
58         if(++cnt >= k) return true;
59     }
60     return false;
61 }
62
63 int main()
64 {
65     //freopen("in.txt", "r", stdin);
66
67     scanf("%d%d", &n, &k);
68     for(int i = 0; i < n; i++)
69     {
70         scanf("%d", &s[i]);
71         s[i]++;
72     }
73     s[n] = 0;
74     build_sa(1000002);
75     build_height();
76
77     int L = 1, R = n;
78     while(L < R)
79     {
80         int M = (L + R + 1) / 2;
81         if(ok(M)) L = M;
82         else R = M - 1;
83     }
84
85     printf("%d\n", L);
86
87     return 0;
88 }

代码君

时间: 2024-08-09 22:00:16

POJ 3261 (后缀数组 二分) Milk Patterns的相关文章

poj 3261 后缀数组 找重复出现k次的子串(子串可以重叠)

题目:http://poj.org/problem?id=3261 仍然是后缀数组的典型应用----后缀数组+lcp+二分 做的蛮顺的,1A 但是大部分时间是在调试代码,因为模板的全局变量用混了,而自己又忘了,,,等西安邀请赛还有四省赛结束之后,该冷静反思下尝试拜托模板了 错误   :1.k用错,题目的k和模板的k用混; 2.还是二分的C()函数,这个其实跟前一篇<poj 1226 hdu 1238 Substrings 求若干字符串正串及反串的最长公共子串 2002亚洲赛天津预选题>的C函数

poj 3261 后缀数组 找反复出现k次的子串(子串能够重叠)

题目:http://poj.org/problem?id=3261 仍然是后缀数组的典型应用----后缀数组+lcp+二分 做的蛮顺的,1A 可是大部分时间是在调试代码.由于模板的全局变量用混了,而自己又忘了.,,等西安邀请赛还有四省赛结束之后,该冷静反思下尝试拜托模板了 错误   :1.k用错,题目的k和模板的k用混; 2.还是二分的C()函数,这个事实上跟前一篇<poj 1226 hdu 1238 Substrings 求若干字符串正串及反串的最长公共子串 2002亚洲赛天津预选题>的C函

POJ 2774 后缀数组 || 二分+哈希

Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 35607   Accepted: 14275 Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days

[poj 3261]后缀数组+滑窗最小值

题目链接:http://poj.org/problem?id=3261 这个是可以交叉的重复串,所以用height就可以了,但是题目说让重复k次以上,也就是直接做一个k-1长度的滑窗最小值,从这些最小值里取最大即可. 这里其实为了节省空间可以先给数字离散化一下,这样就只有20000了,不过不离散化空间也够用. #include<cstdio> #include<algorithm> #include<cstring> #include<queue> usin

poj 3261 Milk Patterns 后缀数组+二分

1 /*********************************************************** 2 题目: Milk Patterns(poj 3261) 3 链接: http://poj.org/problem?id=3261 4 题意: 给一串数字,求这些数字中公共子串个数大于k的 5 最长串. 6 算法: 后缀数组+二分 7 ***********************************************************/ 8 #incl

POJ 1226后缀数组:求出现或反转后出现在每个字符串中的最长子串

思路:这题是论文里的最后一道练习题了,不过最后一题竟然挺水的. 因为求的是未反转或者反转后,最长公共子串. 刚开始还真不知道怎么构建连接成一个字符串,因为需要有反转嘛! 但是其实挺简单的,把未反转的和反转后的字符串都连起来,中间用未出现过的字符隔开就行了!然后未反转的和反转的在同一组. 二分枚举最长的公共前缀长度,然后统计看看这个最长的长度在不在所有的组里,如果在就符合-- #include<iostream> #include<cstdio> #include<cstrin

POJ 3294 后缀数组:求不小于k个字符串中的最长子串

思路:先把所有的串连接成一个串,串写串之前用没出现过的字符隔开,然后求后缀:对height数组分组二分求得最长的公共前缀,公共前缀所在的串一定要是不同的,不然就不是所有串的公共前缀了,然后记下下标和长度即可. 刚开始理解错题意,然后不知道怎么写,然后看别人题解也不知道怎么意思,后面看了好久才知道题目意思理解错了. 时间四千多ms,别人才一百多ms,不知道别人怎么做的-- #include<iostream> #include<cstdio> #include<cstring&

POJ 1743 后缀数组:求最长不重叠子串

数据:这题弄了好久,WA了数十发,现在还有个例子没过,可却A了,POJ 的数组也太弱了. 10 1 1 1 1 1 1 1 1 1 1 这组数据如果没有那个n-1<10判断的话,输入的竟然是5,我靠-- 思路:这个题目关键的地方有两个:第一,重复的子串一定可以看作是某两个后缀的公共前缀,第二,把题目转化成去判定对于任意的一个长度k,是否存在长度至少为k的不重叠的重复的子串. 转化成判定问题之后,就可以二分去解答了.在验证判定是否正确时,我们可以把相邻的所有不小于k的height[]看成一组,然后

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the