HihoCoder
来源:互联网 发布:全球语音翻译软件 编辑:程序博客网 时间:2024/06/08 05:11
题目链接
题意:
小Hi想知道一段旋律中出现次数至少为K次的旋律最长是多少?
思路:
这个题目应该是后缀数组的几个经典之一.
首先要求重叠的最长,那么我们可以知道我们对所有的后缀排个序的话,字典序越接近的他的前缀越长,这是很显然的.也就是我们的height数组.
接着我们就可以想到求n个后缀的最长公共前缀:
①首先将N个字符串按照字典序排列。
②计算height(2), height(3)... height(n),得到height序列。
③最后,height序列中的最小元素的值,就是N个字符串的最长公共前缀的长度。
所以我们可以想到,我要求至少重复k次的最长公共前缀,那么我只需要找到height数组中,连续的k-1个的最小值,这代表的就是出现了k次的每个公共前缀的数量,然后维护一下这个的最大值就是最终的结果了.
PS: 我们只需要维护出现k次就好了,可以想一下题目要求至少为k次,我们按照字典序排序后,k+1个字符的最长公共前缀是小于等于k个字符的最长公共前缀的.
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define inf 0x3f3f3f3f using namespace std; const int maxn = 1e5+5; int t1[maxn], t2[maxn], c[maxn]; //c 基数排序辅助数组int a[maxn];int ra[maxn], height[maxn]; //rank数组,高度数组 int sa[maxn]; //suffix array int n; bool cmp(int *r, int a, int b, int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int str[], int sa[], int ra[], int height[], int n, int m) { n++; int i, j, p, *x = t1, *y = t2; for(i = 0; i < m; i++) c[i] = 0; for(i = 0; i < n; i++) c[x[i]=str[i]]++; for(i = 1; i < m; i++) c[i] += c[i-1]; for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i; for(j = 1; j <= n; j<<=1) { p = 0; for(i = n-j; i < n; i++) y[p++] = i; for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j; for(i = 0; i < m; i++) c[i] = 0; for(i = 0; i < n; i++) c[x[y[i]]]++; for(i = 1; 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]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++; if(p >= n) break; m = p; } int k = 0; n--; for(i = 0; i <= n; i++) ra[sa[i]] = i; for(i = 0; i < n; i++) { if(k) k--; j = sa[ra[i]-1]; while(str[i+k]==str[j+k]) k++; height[ra[i]] = k; } } int main() { // freopen("a.in","r",stdin); int n,K; while(cin>>n>>K) { for(int i=0;i<n;i++) scanf("%d",&a[i]); da(a,sa,ra,height,n,127); if(K==0){printf("%d\n",n);continue;}int ans=0;for(int i=1;i<=n-K+1;i++){int mm=inf;for(int j=0;j<K-1;j++){ if(mm>height[i+j]) mm=height[i+j];}if(mm>ans)ans=mm;} printf("%d\n",ans);}}
这个题还有另外一种做法就是二分.类似于最小值最大化问题,所以我们可以想到二分这个旋律的长度然后带回验证.
道理是一样的,将连续的height数组划分集合,舍掉所有LCP小于mid的,然后重新划分.这样就保证了得到的每一个集合中的LCP都说>=mid,如果有一个集合中的字符串数量>=k就满足.
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1e5+5; int t1[maxn], t2[maxn], c[maxn]; int ra[maxn], height[maxn]; int sa[maxn], num[maxn]; bool cmp(int *r, int a, int b, int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int str[], int sa[], int ra[], int height[], int n, int m) { n++; int i, j, p, *x = t1, *y = t2; for(i = 0; i < m; i++) c[i] = 0; for(i = 0; i < n; i++) c[x[i]=str[i]]++; for(i = 1; i < m; i++) c[i] += c[i-1]; for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i; for(j = 1; j <= n; j<<=1) { p = 0; for(i = n-j; i < n; i++) y[p++] = i; for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i]-j; for(i = 0; i < m; i++) c[i] = 0; for(i = 0; i < n; i++) c[x[y[i]]]++; for(i = 1; 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]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++; if(p >= n) break; m = p; } int k = 0; n--; for(i = 0; i <= n; i++) ra[sa[i]] = i; for(i = 0; i < n; i++) { if(k) k--; j = sa[ra[i]-1]; while(str[i+k]==str[j+k]) k++; height[ra[i]] = k; } } int n, k; bool judge(int x) { int tmp = 1; for(int i = 1; i < n; ) { int cnt = 1; int j = i+1; while(height[j] >= x && j <= n) j++, cnt++; tmp = max(tmp, cnt); i = j; } return tmp >= k; } int main(void) { while(cin >> n >> k) { for(int i = 0; i < n; i++) scanf("%d", &num[i]); da(num, sa, ra, height, n, 127); int l = 0, r = n, ans = 0; while(l <= r) { int mid = (l+r)/2; if(judge(mid)) ans = mid, l = mid+1; else r = mid-1; } printf("%d\n", ans); } return 0; }
最后附上一个不错的博客.
阅读全文
0 0
- hihocoder:
- hihoCoder
- Hihocoder
- hihocoder
- hihocoder
- hihocoder
- hihocoder
- hihocoder
- HihoCoder
- HihoCoder
- HihoCoder
- HihoCoder
- HihoCoder
- HihoCoder
- hihoCoder
- HihoCoder
- HihoCoder
- HihoCoder
- 截图存储到SD卡
- STL的二级空间配置器和malloc
- 直方图内最大矩形问题
- Elasticsearch5.4.0(head/kibana/logstash)安装部署深入详解
- 不同类型数据间的转换
- HihoCoder
- 阿里云域名+老薛主机 搭建个人博客网站 小结
- 根据条件控制Grid列能否编辑
- RESTful笔记
- 正则表达式入门
- Leetcode: Binary Tree Zigzag Level Order Traversal
- 多校联合赛第二场Mammum Sequence(贪心)
- Codeforces Round #425 (Div. 2)比赛总结
- svn