后缀数组 最长不可重叠重复子串问题
来源:互联网 发布:感动一个人 知乎 编辑:程序博客网 时间:2024/06/06 03:39
时间限制:5000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为长度为 N 的数构成的数列。小Hi在练习过很多曲子以后发现很多作品自身包含一样的旋律。
旋律可以表示为一段连续的数列,相似的旋律在原数列不可重叠,比如在1 2 3 2 3 2 1 中 2 3 2 出现了一次,2 3 出现了两次,小Hi想知道一段旋律中出现次数至少为两次的旋律最长是多少?
解题方法提示
输入
第一行一个整数 N。1≤N≤100000
接下来有 N 个整数,表示每个音的数字。1≤数字≤1000
输出
一行一个整数,表示答案。
样例输入
8
1 2 3 2 3 2 3 1
样例输出
2
小Ho:这一次的问题该如何解决呢?
小Hi:嗯,这次的问题被称为最长不可重叠重复子串问题。
小Ho:和上次的问题好像啊,但是这一次是不可以重叠的,直接使用上次的算法似乎行不通喔。
小Hi:是的。问题的关键就出在直接用 height 数组不能保证两后缀不重叠,我们得换个思路考虑。
小Ho:可不可以二分答案,转化成判定问题呢?
小Hi:是个好思路,这的确是可行的。我们先二分一个k,表示我们假设串中存在长度为k的不可重叠重复子串。
小Ho:嗯,就是这个意思。
小Hi:存在长度为k的不可重复子串等价于存在两个后缀有长度为k的公共前缀(这里没有要求不重叠)。我们检查 height 数组中有哪些值 ≥ k。并且如果有连续的height值 ≥ k,就把对应的后缀分在同一组。这样就保证了该组中所有后缀两两之间的最长公共前缀都是不小于k的。
我们以样例为例,看一下k=2和k=3的情况。
x i height k=2 k=3
1 8 0
1 2 3 2 3 2 3 1 1 1
2 3 1 6 0
2 3 2 3 1 4 2 >=2
2 3 2 3 2 3 1 2 4 >=2 >=3
3 1 7 0
3 2 3 1 5 1
3 2 3 2 3 1 3 3 >=2 >=3
可以看出,当k=2时,”231”和”23231”的公共前缀大于等于k,”23231”和”2323231”的公共前缀也大于等k,所以这3个排名连续的后缀会被分到一组。同理”3231”和”323231”也会被分到一组。
对于k=3,”23231”和”2323231”分到一组,”3131”和”323231”分到一组。
小Ho:我知道了!
小Hi:对,没错!下面我们要看看能不能找出不重叠的重复子串。对于每一组,我们检查这些后缀对应的sa值(也就是后缀起点在原串中的位置i)。如果max{sa} - min{sa} >= k,那么就说明我们能找出一组不重叠的重复子串。
例如对于k=3,”23231”和”2323231”的sa值是4和2,”3131”和”323231”这一组的sa值是5和3,差值都不满足大于等于3,所以找不出不重叠的。
对于k=2,第一组max{sa}-min{sa}=6-2=4满足大于等于2,所以能找出不重叠的。
因为只用统计两次 所以 不同统计次数
#include <bits/stdc++.h>using namespace std;const int MAXN = 101000;int t1[MAXN],t2[MAXN],c[MAXN];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 ra[MAXN],height[MAXN];int sa[MAXN],num[MAXN];bool ok(int k){ int ans=0; for(int i=1;i<=n;i++) { if(height[i]<k) continue; int maxx=max(sa[i-1],sa[i]),minn=min(sa[i-1],sa[i]); int j=i; while(height[j+1]>=k&&j<=n) { j++,maxx=max(maxx,sa[j]),minn=min(minn,sa[j]); } if(maxx-minn>=k) return 1; } return 0;}int main(){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&num[i]); num[n]=0; da(num,sa,ra,height,n,1001); int l=0,r=n; while(l<=r) { int mid=(l+r)>>1; if(ok(mid)) l=mid+1; else r=mid-1; } printf("%d\n",l-1 );}
- 后缀数组 最长不可重叠重复子串问题
- poj1743(后缀数组+二分--不可重叠最长重复子串)
- 不可重叠的最长重复子串(后缀数组)
- 后缀数组(不可重叠最长重复子串)
- 【后缀数组】不可重叠最长重复子串
- Hiho 121 后缀数组二·重复旋律2(最长不可重叠重复子串问题)
- 后缀数组--(可重叠最长重复子串问题)
- 后缀数组模版 及 可重叠和不可重叠最长重复子串【for_wind】
- hihoCoder 1407 后缀数组二·重复旋律2 && POJ 1743 Musical Theme(最长不可重叠重复子串问题)
- poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串
- 【后缀数组求不可重叠最长重复子串】POJ 1743
- POJ 1743 Musical Theme(后缀数组求不可重叠最长重复子串)
- poj 1743 字符串 后缀数组 不可重叠最长重复子串
- PKU1743(Musical Theme)求不可重叠最长重复子串(后缀数组+二分)
- Poj 1743 Musical Theme (后缀数组 不可重叠最长重复子串)
- poj 1743 Musical Theme (后缀数组 不可重叠最长重复子串)
- poj 1743 Musical Theme(不可重叠的最长重复子串,后缀数组)
- POJ 1743 Musical Theme ( 后缀数组 + 二分 不可重叠最长重复子串 )
- 机器学习与深度学习(六) 聚类(Clustering)____K-均值聚类算法(K-means Clustering) 层次聚类(Hierarchical Clustering)
- Objective-c runtime及消息机制
- Python的由来
- 0030_Substring with Concatenation of All Words
- 第8章 diff
- 后缀数组 最长不可重叠重复子串问题
- 数据压缩原理与应用 H.264编码
- RecyclerView的点击事件
- final、finally、finalize的作用
- 震撼【超高细节地球】GIS相关引擎研发,速看(数字地球,地理信息系统)
- sql2012+thinkphp链接以及部署
- tcp阻断模块实现和测试
- 构造方法与方法重载
- 跳过权限检查,强制修改mysql密码 windows: 1,停止MYSQL服务,CMD打开DOS窗口,输入 net stop mysql 2,在CMD命令行窗口,进入MYSQL安装目录 比如E: