标签:
传送门:http://poj.org/problem?id=3693
题目:给出一个串,求重复次数最多的连续重复子串;
分析:
枚举重复单元的长度,然后理所当然的枚举起点。利用rmq处理,后缀i,i+l的最长前缀。
lcp/l+1,为当前相邻l长度单元的串的重复次数,但是由于i+=l,提高了效率,但是i不一定刚好是重复串的起点,所以如果r%l!=0,把串往前移l-r%l个单位。找到最大的重复次数,然后利用sa数组的排名(1-n),,可以字典序输出。
详细链接:http://blog.csdn.net/acm_cxlove/article/details/7941205
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<string> #include<queue> #include<deque> #include<stack> #include<map> #include<set> #define INF 0x7fffffff #define SUP 0x80000000 #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long LL; const int N=100007; /******************auther:ACsorry******************/ //以下为倍增算法求后缀数组 int wa[N],wb[N],wv[N],Ws[N]; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(const char *r,int *sa,int n,int m){ int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) Ws[i]=0; for(i=0;i<n;i++) Ws[x[i]=r[i]]++; for(i=1;i<m;i++) Ws[i]+=Ws[i-1]; for(i=n-1;i>=0;i--) sa[--Ws[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++) Ws[i]=0; for(i=0;i<n;i++) Ws[wv[i]]++; for(i=1;i<m;i++) Ws[i]+=Ws[i-1]; for(i=n-1;i>=0;i--) sa[--Ws[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++; } return; } int sa[N],Rank[N],height[N]; //求height数组 void calheight(const char *r,int *sa,int n){ 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++); return; } int dp[N][20]; void Rmq_init(int n) { int m=floor(log(n+0.0)/log(2.0)); for(int i=1;i<=n;i++) dp[i][0]=height[i]; for(int j=1;j<=m;j++){ for(int i=1;i+(1<<j)-1<=n;i++){ dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } } int Rmq_query(int L,int R) { int a=Rank[L],b=Rank[R]; if(a>b) swap(a,b); a++;//这个地方++,应为height[a]处理的是 a,a-1的公共串 int m=floor((log(b-a+1.0)/log(2.0))); return min(dp[a][m],dp[b-(1<<m)+1][m]); } char str[N]; int main() { int cas=0; while(scanf("%s",str)==1&&str[0]!='#') { int n=strlen(str); da(str,sa,n+1,130); calheight(str,sa,n); Rmq_init(n); int cnt=0,maxx=0,a[N]; for(int l=1;l<n;l++){ for(int i=0;i+l<n;i+=l){ //j+=l.复杂度的需要 int r=Rmq_query(i,i+l); int step=r/l+1; int k=i-(l-r%l); if(k>=0&&r%l){ if(Rmq_query(k,k+l)>=r) step++; } if(step>maxx) { maxx=step; cnt=0; a[cnt++]=l; } else if(step==maxx) a[cnt++]=l; } } int len=-1,st; for(int i=1;i<=n&&len==-1;i++){ for(int j=0;j<cnt;j++){ if(Rmq_query(sa[i],sa[i]+a[j])/a[j]+1==maxx) { len=a[j]; st=sa[i]; break; } } } str[st+maxx*len]=0; printf("Case %d: %s\n",++cas,str+st); } return 0; }
//宁愿精彩的活,也不愿平庸一辈子。
poj 3693 Maximum repetition substring(08合肥 RMQ+后缀数组)
标签:
原文地址:http://blog.csdn.net/code_or_code/article/details/45182711