转载请注明出处:http://blog.csdn.net/vmurder/article/details/42677359
其实我就是觉得原创的访问量比未授权盗版多有点不爽233。。。
题意:
给一个字符串,然后找一个子串,使子串满足其中连续重复子串最多。
比如ababab,重复次数为3,ababa,重复次数为1(abab是两次)
恶心在于还要输出最小字典序。
题解网上都有,不发了。
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 101000 #define LOGN 20 #define inf 0x3f3f3f3f using namespace std; char s[N]; int len; int sa[N],rank[N],height[N]; int sa2[N],rank2[N],height2[N]; int stk[N],top,cnt[N]; int val[N],_val[N]; inline bool cmp(int x,int y,int hl) {return val[x]==val[y]&&((x+hl>=len&&y+hl>=len)||(x+hl<len&&y+hl<len&&val[x+hl]==val[y+hl]));} void SA() { int i,j,k,hl,lim=300; for(i=0;i<lim;i++)cnt[i]=0; for(i=0;i<len;i++)cnt[val[i]=s[i]]++; for(i=1;i<lim;i++)cnt[i]+=cnt[i-1]; for(i=len-1;i>=0;i--)sa[--cnt[val[i]]]=i; for(k=0;;k++) { top=0,hl=1<<k; for(i=0;i<len;i++)if(sa[i]+hl>=len)stk[++top]=sa[i]; for(i=0;i<len;i++)if(sa[i]>=hl)stk[++top]=sa[i]-hl; for(i=0;i<lim;i++)cnt[i]=0; for(i=0;i<len;i++)cnt[val[i]]++; for(i=1;i<lim;i++)cnt[i]+=cnt[i-1]; for(i=len;i>0;i--)sa[--cnt[val[stk[i]]]]=stk[i]; for(i=lim=0;i<len;lim++) { for(j=i;j<len-1&&cmp(sa[j],sa[j+1],hl);j++); for(;i<=j;i++)_val[sa[i]]=lim; } for(i=0;i<len;i++)val[i]=_val[i]; if(lim==len)break; } for(i=0;i<len;i++)rank[sa[i]]=i; for(k=i=0;i<len;i++) { if(k)k--; if(!rank[i])continue; while(s[i+k]==s[sa[rank[i]-1]+k])k++; height[rank[i]]=k; } lim=300; for(i=0;i<lim;i++)cnt[i]=0; for(i=0;i<len;i++)cnt[val[i]=s[len-i-1]]++; for(i=1;i<lim;i++)cnt[i]+=cnt[i-1]; for(i=len-1;i>=0;i--)sa2[--cnt[val[i]]]=i; for(k=0;;k++) { top=0,hl=1<<k; for(i=0;i<len;i++)if(sa2[i]+hl>=len)stk[++top]=sa2[i]; for(i=0;i<len;i++)if(sa2[i]>=hl)stk[++top]=sa2[i]-hl; for(i=0;i<lim;i++)cnt[i]=0; for(i=0;i<len;i++)cnt[val[i]]++; for(i=1;i<lim;i++)cnt[i]+=cnt[i-1]; for(i=len;i>0;i--)sa2[--cnt[val[stk[i]]]]=stk[i]; for(i=lim=0;i<len;lim++) { for(j=i;j<len-1&&cmp(sa2[j],sa2[j+1],hl);j++); for(;i<=j;i++)_val[sa2[i]]=lim; } for(i=0;i<len;i++)val[i]=_val[i]; if(lim==len)break; } for(i=0;i<len;i++)rank2[sa2[i]]=i; for(k=i=0;i<len;i++) { if(k)k--; if(!rank2[i])continue; while(s[len-i-k-1]==s[len-sa2[rank2[i]-1]-k-1])k++; height2[rank2[i]]=k; } } int st[N][LOGN],St[N][LOGN],logf[N]; int ST[N][LOGN],sT[N][LOGN]; void RMQ_init() { int i,j,k,sk; for(i=0;i<len;i++) { st[i][0]=height[i]; St[i][0]=height2[i]; sT[i][0]=rank[i]; ST[i][0]=i; } for(i=2;i<N;i++)logf[i]=logf[i>>1]+1; for(j=1;k=(1<<j),k<len;j++) for(sk=(k>>1),i=0;i+k-1<len;i++) { st[i][j]=min(st[i][j-1],st[i+sk][j-1]), St[i][j]=min(St[i][j-1],St[i+sk][j-1]); if(sT[i][j-1]<sT[i+sk][j-1]) { sT[i][j]=sT[i][j-1]; ST[i][j]=ST[i][j-1]; } else { sT[i][j]=sT[i+sk][j-1]; ST[i][j]=ST[i+sk][j-1]; } } } inline int querypre(int L,int R) // 两个点最长相同前串 { if(L>R)swap(L,R);L++; int ll=logf[R-L]; return min(St[L][ll],St[R-(1<<ll)+1][ll]); } inline int querysuc(int L,int R) // 两个点最长相同后串 { if(L>R)swap(L,R);L++; int ll=logf[R-L]; return min(st[L][ll],st[R-(1<<ll)+1][ll]); } inline int query(int L,int R) // 求一段区间内最小rank { if(L>R)swap(L,R); int ll=logf[R-L]; return sT[L][ll]<sT[R-(1<<ll)+1][ll]?ST[L][ll]:ST[R-(1<<ll)+1][ll]; } int ans,id,id2; int main() { // freopen("test.in","r",stdin); int i,j,k,g=0; int l,r,pre,suc,ll; while(scanf("%s",s),s[0]!='#') { printf("Case %d: ",++g); len=strlen(s); SA(); RMQ_init(); ans=1,id=0,id2=1; for(i=len>>1;i;i--) // 枚举 重复部分 长度 { for(j=0;j+i<len;j+=i) { pre=querypre(rank2[len-j-1],rank2[len-j-i-1]); suc=querysuc(rank[j],rank[j+i]); ll=(pre&&suc)?(pre+suc-1):(pre+suc); if(k=ll/i) { l=j-pre+(pre?1:0); r=l+ll-k*i; int mx=query(l,r); k++; if(ans<k||(ans==k&&rank[id]>=rank[mx])) ans=k,id=mx,id2=id+k*i; } } } if(ans==1)printf("%c\n",s[sa[0]]); for(i=id;i<id2;i++)printf("%c",s[i]); puts(""); } return 0; }