【HDU2890 Longest Repeated subsequence】 后缀数组之重复k次最长子序列(不可覆盖)
2013-04-21 14:57
260 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2890
题目大意:给你一个含n个数的序列,再给你一个k,让你求最少重复k次的最长子序列(子序列不能重叠)。
解题思路:先吐槽一下,题意不明,蛋疼许久。
我可以这么理解 : 1、保证子序列重复次数cnt大于k的前提下,len为一个子序列长度,然后最长子序列最长,即cnt*len最大。
2、保证子序列重复次数cnt大于k的前提下,只需让子序列长度len最长即可。
我在理解1中挣扎了许久才发现我题目都理解错了,题目意思是理解2,擦擦擦。
这题X值很大,先离散化处理一下。 以前写过一道最少重复k次子序列可相互覆盖的题目,这题是不可覆盖。所以这里要特殊处理一下,开始我用标记,后来发现处理的时候还是有点问题,后来改成贪心做,即多开一个que数组,记录sa[]值,每次遇见height<mid(枚举的长度)时,对que中序列排序一下,这样就保证了处理的时候就是从左往右了。
View Code
题目大意:给你一个含n个数的序列,再给你一个k,让你求最少重复k次的最长子序列(子序列不能重叠)。
解题思路:先吐槽一下,题意不明,蛋疼许久。
我可以这么理解 : 1、保证子序列重复次数cnt大于k的前提下,len为一个子序列长度,然后最长子序列最长,即cnt*len最大。
2、保证子序列重复次数cnt大于k的前提下,只需让子序列长度len最长即可。
我在理解1中挣扎了许久才发现我题目都理解错了,题目意思是理解2,擦擦擦。
这题X值很大,先离散化处理一下。 以前写过一道最少重复k次子序列可相互覆盖的题目,这题是不可覆盖。所以这里要特殊处理一下,开始我用标记,后来发现处理的时候还是有点问题,后来改成贪心做,即多开一个que数组,记录sa[]值,每次遇见height<mid(枚举的长度)时,对que中序列排序一下,这样就保证了处理的时候就是从左往右了。
View Code
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> using namespace std; const int maxn=50050; char str[maxn]; int num[maxn]; int sa[maxn]; ///(你排第几)下标:排名情况, 数组值:首字符序号 int rank[maxn];/// (排第几的是谁) 下标:首字符序号, 数组值:排名情况 int height[maxn]; /// height[i]表示后缀i和后缀i-1的最长公共前缀 int wa[maxn], wb[maxn], wv[maxn], wd[maxn]; int X[maxn], que[maxn]; int pos; int cmp(int *r, int a, int b, int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int *r, int n, int m){ /// 倍增算法 r为待匹配数组 n为总长度 m为字符范围 int i, j, p, *x = wa, *y = wb, *t; for(i = 0; i < m; i ++) wd[i] = 0; for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++; for(i = 1; i < m; i ++) wd[i] += wd[i-1]; for(i = n-1; i >= 0; i --) sa[-- wd[x[i]]] = i; for(j = 1, p = 1; p < n; j *= 2, m = p){ for(p = 0, 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 < n; i ++) wv[i] = x[y[i]]; for(i = 0; i < m; i ++) wd[i] = 0; for(i = 0; i < n; i ++) wd[wv[i]] ++; for(i = 1; i < m; i ++) wd[i] += wd[i-1]; for(i = n-1; i >= 0; i --) sa[-- wd[wv[i]]] = y[i]; for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++){ x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1: p ++; } } } void calHeight(int *r, int n){ /// 求height数组。 int i, j, k = 0; for(i = 1; i <= n; i ++) rank[sa[i]] = i; for(i = 0; i < n; height[rank[i ++]] = k){ for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++); } } int find(int tmp, int n) { int l=0, r=n, mid; while(l<=r) { mid=(l+r)>>1; if(X[mid]==tmp) return mid; else if(X[mid]<tmp) l=mid+1; else r=mid-1; } } bool judge(int mid, int rear, int k) { sort(que,que+rear); int pre=que[0], cnt=1; for(int i=1; i<rear; i++) if(que[i]-pre>=mid) pre=que[i], cnt++; return cnt>=k; } bool check(int mid, int n, int k) { int rear=0; for(int i=1; i<=n; i++) { if(height[i]<mid) { if(judge(mid,rear,k)) { pos=sa[i-1]; return true; } rear=0, que[rear++]=sa[i]; } else que[rear++]=sa[i]; } if(judge(mid,rear,k)) { pos=sa[n-1]; return true; } return false; } int main() { int n, k, T; cin >> T; while(T--) { scanf("%d%d",&n,&k); for(int i=0; i<n; i++) scanf("%d",num+i), X[i]=num[i]; sort(X,X+n); int ep=0; for(int i=1; i<n; i++) if(X[i]!=X[ep]) X[++ep]=X[i]; for(int i=0; i<n; i++) num[i]=find(num[i],ep)+2; num =0; da(num,n+1,n+5); calHeight(num,n); int l=1, r=n, mid, ans=0; while(l<=r) { mid=(l+r)>>1; if(check(mid,n,k)) { l=mid+1; ans=mid; } else r=mid-1; } printf("%d\n",ans); for(int i=pos; i<pos+ans; i++) printf("%d\n",X[num[i]-2]); if(T) puts(""); } return 0; }
相关文章推荐
- poj 3261 Milk Patterns 最长的出现最少k次的重复(可重叠)子串 后缀数组
- 后缀数组 最长不可重叠重复子串问题
- POJ - 1743 - Musical Theme(后缀数组 - 不可重叠最长重复子串)
- 最长子序列回文问题,Longest Palindromic Subsequence
- POJ 3261 Milk Patterns (后缀数组,求可重叠的k次最长重复子串)
- poj 1743 字符串 后缀数组 不可重叠最长重复子串
- poj 3261 Milk Patterns(最长至少k次重复子串,后缀数组基础题)
- poj 3261(后缀数组,求可重叠的k次最长重复子串)
- poj1743(后缀数组+二分--不可重叠最长重复子串)
- HDU3518 后缀数组求不可重叠重复出现的不同子串个数
- LCS(longest common subsequence)与LCS(longest common substring)以及后缀数组
- POJ 1743 Musical Theme (后缀数组加二分求不可重叠最长重复子串)
- POJ-3261 Milk Patterns (后缀数组 最长k次重复子串)
- 后缀数组模版 及 可重叠和不可重叠最长重复子串【for_wind】
- 【poj1743-Musical Theme】不可重叠最长重复子串-后缀数组
- 后缀数组(不可重叠重复子串)poj1743
- poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串
- poj1743 Musical Theme(后缀数组--不可重叠最长重复子串+二分)
- POJ 1743 Musical Theme(不可重叠最长重复子串 后缀数组)
- POJ - 1743 Musical Theme (后缀数组求不可重叠最长重复子串)