poj3693 ,spoj687 重复次数最多的连续重复子串 后缀数组
来源:互联网 发布:淘宝万斯正品店 编辑:程序博客网 时间:2024/05/17 04:25
给一个字符串,给定一个字符串,求重复次数最多的连续重复子串。
09年罗穗骞的论文里有讲这题,先引用一下论文里的讲解:
先穷举长度L,然后求长度为L 的子串最多能连续出现几次。首先连续出现1 次是肯定可以的,所以这里只考虑至少2 次的情况。假设在原字符串中连续出现2 次,记这个子字符串为S,那么S 肯定包括了字符r[0], r[L], r[L*2],r[L*3], ……中的某相邻的两个。所以只须看字符r[L*i]和r[L*(i+1)]往前和往后各能匹配到多远,记这个总长度为K,那么这里连续出现了K/L+1 次。最后看最大值是多少。如图7 所示。
穷举长度L 的时间是n,每次计算的时间是n/L。所以整个做法的时间复杂度是O(n/1+n/2+n/3+……+n/n)=O(nlogn)。
以上内容提供了一个思路方向,但剩下的东西也挺难想的...论文里只讲了右面匹配的情况,队向左匹配的方法并没有细说(难道是认为太简单了么....= =.....),举个例子吧(数据是从poj discuss里搬来的)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
b a c c d b a c c d b a c b d b a c b d
加入我现在枚举到了l=5,p1=5,p2=10
令k=LCS(p1,p2)=3(bac),
而重复的次数即c=k/l+1=1;
由于本题要输出字典序最小的答案,所以p1-l+1 -----p1-1之间任何一个位置都可能是我们要的答案,所以我们必须在字符匹配的情况下逐位向前平移去找答案,
移动两位后,p1=3,p2=8,此时k也增加2等于5,发现达到了l,所以此时c++,等于2,之后发现再往前平移字符依然是匹配的,所以继续,找到p1=1,p2=6,此时k=7,c=2,重复的次数和p1在3的时候没有变化,但显然此时的字典序是更小的,所以在这里更新答案的位置,下一位字符不再匹配,所以到此结束。
这样按照论文中的做法,把长度枚举一边即可得到答案。要说一下的是,这么去找最小的字典序的话,最差的情况其实还是n^2的(比如构造50000个a,跑出来结果就要将近10s),可能是数据给的太弱了(网上搜了几个题解,好多代码都被discuss里给的数据cha掉了...),这么写再poj上只用了400ms。我也没什么别的好方法了...还望大神赐教...
spoj687这题就好办了,只要求输出最大的重复次数,和上面的方法一样。枚举长度,然后枚举i*l,(i+1)*l的位置,由于不求字符串,这里我们便可以省去平移。求出k之后,若k%l>0的话,说明p1,p2之前的位置也可能有匹配的情况,所以找到p3=p1-(l-k%l),若此时LCS(p3,p3+l)>k,那么说明前面这l-k%l位也是匹配的,所以k+=(l-k%l)。此时c=k/l+1就是我们要的答案。
贴两个代码了,
poj3693
#include <iostream>#include <cstdio>#include <algorithm>#include <string>#include <cstring>using namespace std;typedef long long ll;const int maxn=220100;int s[maxn],ss[maxn];int sa[maxn],t[maxn],t2[maxn],c[maxn];int sa2[maxn];char s1[maxn],s2[maxn];int rank[maxn],height[maxn];int rank2[maxn],height2[maxn];int l1,l2;int len,len1;int n,m;inline int idx(char s){ return s-'a'+1;}void getheight(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--; int j=sa[rank[i]-1]; while(s[i+k]==s[j+k]) k++; height[rank[i]]=k; }}void build_ss(int m,int n){ n++; int i,*x=t,*y=t2; for (int i=0; i<m; i++) c[i]=0; for (int i=0; i<n; i++) c[x[i]=s[i]]++; for (int i=1; i<m; i++) c[i]+=c[i-1]; for (int i=n-1; i>=0; i--) sa[--c[x[i]]]=i; for (int k=1; k<=n; k<<=1) { int p=0; for (i=n-k; i<n; i++) y[p++]=i; for (i=0; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k; 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]+k]==y[sa[i]+k])? p-1 : p++; if (p>=n) break; m=p; }}int d[maxn][22];void RMQ_init(){ for (int i=1; i<=n; i++) d[i][0]=height[i]; for (int j=1; (1<<j)<=n; j++) for (int i=1; (i+(1<<j)-1)<=n; i++) d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);}int RMQ(int L,int R){ if (L>R) swap(L,R); L++; int k=0; while((1<<(k+1))<=R-L+1) k++; return min(d[L][k],d[R-(1<<k)+1][k]);}int main(){// freopen("in.txt","r",stdin); int tt=0; while(~scanf("%s",s1) && s1[0]!='#') { n=strlen(s1); for (int i=0; i<n; i++) s[i]=idx(s1[i]); s[n]=0; build_ss(30,n); getheight(n); RMQ_init(); int ans=0,pos=-1,len=0; for (int l=1; l<=n/2; l++) { for (int i=0; (i+1)*l<n; i++) { int p1=i*l,p2=(i+1)*l; int k=RMQ(rank[p1],rank[p2]); int c=k/l+1; int r=l-k%l; int p=i*l; int cnt=0; for (int j=p1-1; j>p1-l&&s[j]==s[j+l]&&j>=0; j--) { cnt++; if (cnt==r) { c++; p=j; } if (rank[j]<rank[p]) p=j; } if (ans<c) { pos=p; ans=c; len=l*c; } else if (ans==c) { if (rank[pos]>rank[p]) { pos=p; len=l*c; } } } } cout<<"Case "<<++tt<<": "; for (int i=0,j=pos; i<len; i++,j++) cout<<s1[j]; cout<<endl; }}
spoj687的话,上面的代码也能过,只不过要跑10s+,若用删掉平移的过程,可以把时间降到4s+
#include <iostream>#include <cstdio>#include <algorithm>#include <string>#include <cstring>using namespace std;typedef long long ll;const int maxn=120100;int s[maxn],ss[maxn];int sa[maxn],t[maxn],t2[maxn],c[maxn];char s1[maxn],s2[maxn];int rank[maxn],height[maxn];int l1,l2;int len,len1;int n,m;inline int idx(char s){ return s-'a'+1;}void getheight(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--; int j=sa[rank[i]-1]; while(s[i+k]==s[j+k]) k++; height[rank[i]]=k; }}void build_ss(int m,int n){ n++; int i,*x=t,*y=t2; for (int i=0; i<m; i++) c[i]=0; for (int i=0; i<n; i++) c[x[i]=s[i]]++; for (int i=1; i<m; i++) c[i]+=c[i-1]; for (int i=n-1; i>=0; i--) sa[--c[x[i]]]=i; for (int k=1; k<=n; k<<=1) { int p=0; for (i=n-k; i<n; i++) y[p++]=i; for (i=0; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k; 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]+k]==y[sa[i]+k])? p-1 : p++; if (p>=n) break; m=p; }}int d[maxn][22];void RMQ_init(){ for (int i=1; i<=n; i++) d[i][0]=height[i]; for (int j=1; (1<<j)<=n; j++) for (int i=1; (i+(1<<j)-1)<=n; i++) d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);}int RMQ(int L,int R){ if (L>R) swap(L,R); L++; int k=0; while((1<<(k+1))<=R-L+1) k++; return min(d[L][k],d[R-(1<<k)+1][k]);}int main(){// freopen("in.txt","r",stdin); int tt=0; scanf("%d",&tt); while(tt--) { scanf("%d",&n); memset(s1,0,sizeof s1); for (int i=0; i<n; i++) scanf("%s",&s1[i]); n=strlen(s1);// puts(s1); for (int i=0; i<n; i++) s[i]=idx(s1[i]); s[n]=0; build_ss(4,n); getheight(n); RMQ_init(); int ans=1,len=0; if (n==0) ans=0; for (int l=1; l<=n/2; l++) { for (int i=0; (i+1)*l<n; i++) { int p1=i*l,p2=(i+1)*l; int k=RMQ(rank[p1],rank[p2]); int r=l-k%l; int p3=p1-r; if (p3>=0 && k%l && RMQ(rank[p3],rank[p3+l])>=k) k+=r; int c=k/l+1; ans=max(ans,c); } } cout<<ans<<endl; }}
- 【后缀数组求重复次数最多的连续重复子串】SPOJ687 POJ3693
- poj3693 ,spoj687 重复次数最多的连续重复子串 后缀数组
- 后缀数组(重复次数最多的连续重复子串)好poj3693+spoj687
- spoj687 重复次数最多的连续重复子串(后缀数组)
- 后缀数组(重复次数最多的连续重复子串)
- POJ 3693 重复次数最多的连续重复子串 后缀数组
- SPOJ 687 Repeats (后缀数组+RMQ 重复次数最多的连续重复子串)
- Maximum repetition substring+POj+后缀数组之求重复次数最多的连续重复子串
- POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)
- poj 3693 后缀数组 重复次数最多的连续重复子串
- poj 3693 重复次数最多的连续重复子串(后缀数组+RMQ)
- SPOJ REPEATS - Repeats(后缀数组[重复次数最多的连续重复子串])
- POJ 3693 Maximum repetition substring(后缀数组[重复次数最多的连续重复子串])
- hihoCoder 1419 后缀数组四·重复旋律4(重复次数最多的连续子串)
- POJ 3693 后缀数组 重复次数最多的连续重复子串 倍增法以及D3法
- poj 3693/hdu 2459 Maximum repetition substring spoj 687. Repeats ( 后缀数组 重复次数最多的连续重复子串)
- poj 1743Maximum repetition substring(后缀数组+RMQ+重复次数最多的连续重复子串))
- 重复次数最多的连续字串 后缀数组板子 黑盒子
- HDU1394最小逆序数
- 达芬奇ICETEK-DM6446-EVMS中xdcpaths.mak
- 给定一个整数N,求N!末尾有多少个0?N!的二进制表示中最低1的位置?
- ubuntu手动安装grub
- 强引用与弱引用(不太懂,不过文章形容的不错)
- poj3693 ,spoj687 重复次数最多的连续重复子串 后缀数组
- 利用SET STATISTICS IO和SET STATISTICS TIME 优化SQL Server查询性能
- Android ViewPager使用详解
- openssl TXT_DB error number 二 failed to update database
- ubuntu 触摸板不能使用的解决办法
- iOS保存数据的4种方式
- Android框架层漏洞-Fragment注入
- Unity3d中shader属性的控制
- python用zipfile模块打包文件或是目录、解压zip文件实例