http://poj.org/problem?id=3693
这题要求在这道题https://www.cnblogs.com/TheRoadToTheGold/p/15141477.html的基础上输出字典序最小的解
这是在上题的基础上的题解
因为在计算最大重复次数的时候,会从分割点往前跳几个字符,得到一个重复子串的起点
所以我输出解的时候,直接拿这个起点的rank作比较了
这是不对的
因为位置靠前不一定字典序小
正确做法是记录所有重复次数相同的循环节长度
然后按sa依次找
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100005 char ch[N]; int n,k,a[N],v[N],p,q,sa[2][N],rk[2][N],h[N]; int f[N][20]; int may[N],tot; void mul(int *sa,int *rk,int *SA,int *RK) { for(int i=1;i<=n;i++) v[rk[sa[i]]]=i; for(int i=n;i;i--) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k; for(int i=n-k+1;i<=n;i++) SA[v[rk[i]]--]=i; for(int i=1;i<=n;i++) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]); } void presa() { p=0; q=1; for(int i=1;i<=26;++i) v[i]=0; for(int i=1;i<=n;i++) v[a[i]]++; for(int i=1;i<=26;i++) v[i]+=v[i-1]; for(int i=1;i<=n;i++) sa[p][v[a[i]]--]=i; for(int i=1;i<=n;i++) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i-1]]!=a[sa[p][i]]); for(k=1;k<n;k<<=1,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]); for(int i=1,k=0;i<=n;i++) { int j=sa[p][rk[p][i]-1]; while(a[i+k]==a[j+k]) k++; h[rk[p][i]]=k;if(k) k--; } } void prest() { for(int i=2;i<=n;++i) f[i][0]=h[i]; for(int i=1;1<<i<=n;++i) for(int j=2;j+(1<<i)-1<=n;++j) f[j][i]=min(f[j][i-1],f[j+(1<<i-1)][i-1]); } int getlcp(int s,int t) { if(t>n) return 0; s=rk[p][s]; t=rk[p][t]; if(s<t) ++s; else { swap(s,t); ++s; } int l=t-s+1; int m=log((double)l)/log((double)2); return min(f[s][m],f[t-(1<<m)+1][m]); } void solve() { int rep=1,sum,lcp,tmp,be,ll=1; prest(); tot=0; for(int i=1;i<n;++i) { for(int j=1;j+i<=n;j+=i) { lcp=getlcp(j,j+i); sum=lcp/i+1; tmp=lcp%i; if(tmp) { if(j-(i-tmp)>0) { lcp=getlcp(j-(i-tmp),j+i-(i-tmp)); if(lcp>=i) ++sum; } } if(sum>rep) { rep=sum; ll=i; may[tot=1]=i; } else if(sum==rep) may[++tot]=i; } } int L=rep*ll; for(int i=1;i<=n;++i) { for(int j=1;j<=tot;++j) if(getlcp(sa[p][i],sa[p][i]+may[j])>=(rep-1)*may[j]) { be=sa[p][i]; for(int i=0;i<L;++i) printf("%c",ch[be+i]); printf(" "); return; } } } int main() { int T=0; while(1) { scanf("%s",ch+1); if(ch[1]=='#') return 0; printf("Case %d: ",++T); n=strlen(ch+1); for(int i=1;i<=n;i++) a[i]=ch[i]-'a'+1; presa(); solve(); } }