hdoj 5030 后缀数组+二分
2015-08-05 19:37
489 查看
hdoj 5030
题意:给一个字符串,最多分割k次,求分割后最大的子串。
思路:
首先通过len - sa[i] - height[i]对子串去重(len是字符串长度),然后枚举最大的子串,看这个子串能否在分割k次以内实现。
第k个子串:
t = lower_bound(sum + 1, sum + 1 + len, k) - sum;// 即子串所属后缀的起始位置, sum[i]是到字符串第i位有多少不同的子串。
L = sa[t], R = len - (sum[t] - k + 1);
关键在于如何分割:因为每个子串都是某个后缀的前缀,所以要在sa[i]+length处分割(length是枚举的子串长度),做标记点(如果这个串是后缀就不用分割),然后遍历当前排名后面的后缀(这后面的后缀才有可能要被分割)做标记,最后在遍历标记找分割点,看是否满足条件,详见代码。
题意:给一个字符串,最多分割k次,求分割后最大的子串。
思路:
首先通过len - sa[i] - height[i]对子串去重(len是字符串长度),然后枚举最大的子串,看这个子串能否在分割k次以内实现。
第k个子串:
t = lower_bound(sum + 1, sum + 1 + len, k) - sum;// 即子串所属后缀的起始位置, sum[i]是到字符串第i位有多少不同的子串。
L = sa[t], R = len - (sum[t] - k + 1);
关键在于如何分割:因为每个子串都是某个后缀的前缀,所以要在sa[i]+length处分割(length是枚举的子串长度),做标记点(如果这个串是后缀就不用分割),然后遍历当前排名后面的后缀(这后面的后缀才有可能要被分割)做标记,最后在遍历标记找分割点,看是否满足条件,详见代码。
#include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 100010; int sa[MAXN]; int t1[MAXN],t2[MAXN],c[MAXN]; int Rank[MAXN],height[MAXN]; void build_sa(int s[],int n,int m) { 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]=s[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]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++; if(p>=n)break; m=p; } } void getHeight(int s[],int n) { int i,j,k=0; for(i=0;i<=n;i++)Rank[sa[i]]=i; for(i=0;i<n;i++) { if(k)k--; j=sa[Rank[i]-1]; while(s[i+k]==s[j+k])k++; height[Rank[i]]=k; } } int seq[MAXN]; void suffix_array(char str[]){ int len = strlen(str); for(int i = 0; i <= len; i++) seq[i] = str[i]; seq[len] = 0; build_sa(seq, len + 1, 128); getHeight(seq, len); } char str[MAXN]; //================================================================================== long long sum[MAXN]; int divide[MAXN], len; bool isOK(long long k, int n) { int t = lower_bound(sum + 1, sum + 1 + len, k) - sum; int l = sa[t], r = len - (sum[t] - k + 1); int LEN = r - l + 1; for(int i = 0; i <= len; i++) divide[i] = -1; if(r + 1 < len) divide[sa[t]] = LEN; for(int i = t + 1; i <= len; i++) {//做标记 LEN = min(LEN, height[i]); if(height[i] == 0) return false; if(sa[i] + LEN < len) divide[sa[i]] = LEN; } int cnt = 0; r = len + 1; for(int i = 0; i < len; i++) {//遍历标记找分割点 if(i == r) { cnt++, r = len + 1; if(cnt >= n) return false; } if(divide[i] != -1) r = min(r, i + divide[i]); } return cnt < n; } main() { int n; while(~scanf("%d", &n) && n) { scanf("%s", str); suffix_array(str); len = strlen(str); for(int i = 1; i <= len; i++) { sum[i] = sum[i - 1] + len - sa[i] - height[i]; } long long l = 1, r = sum[len], ans; while(l <= r) { long long mid = (l + r) / 2; if(isOK(mid, n)) ans = mid, r = mid - 1; else l = mid + 1; } int t = lower_bound(sum + 1, sum + 1 + len, ans) - sum; l = sa[t], r = len - (sum[t] - ans + 1); for(int i = l; i <= r; i++) putchar(str[i]); putchar('\n'); } }
相关文章推荐
- MapReduce中设置文件过滤器代码
- hdu1342 lotto【组合数DFS】
- Spark历险记之编译和远程任务提交
- openstack社区文档贡献
- 08月04日 星期二
- POJ 1581 A Contesting Decision 水
- LCS转为LIS
- ABP(现代ASP.NET样板开发框架)系列之19、ABP应用层——审计日志
- AJAX提交方法(POST)Demon
- jQuery/HTML5响应式焦点图动画应用
- linux LIBRARY_PATH
- Spark历险记之编译和远程任务提交
- Num 20 : HDOJ: 题目1402 : A*B ( 大数问题 )
- C++命名规范
- JSP传递参数到JS中的方法和问题
- HASH表的实现(拉链法) - C/C++
- POJ 1552 Doubles 水
- LeetCode(103) Binary Tree Zigzag Level Order Traversal
- JSP使用EL获取并显示用户注册信息。
- jQuery 3D 女神图片墙 可旋转播放