POJ-3693--字尾陣列求字典序最小重複次數最多子串
阿新 • • 發佈:2018-12-24
摘自2009年國家集訓隊羅穗騫論文《字尾陣列-處理字串的有力工具》
因此我們只需處理出原串正反兩個版本的字尾陣列,然後用rmq問題的處理方法求LCP,我的處理方法是讓關鍵點包含在r中,如果想包含在l中,只需把向前向後擴充套件的位置稍作處理&查詢rank最小值的區間端點分別+1即可。
字典序最小的處理方法摘自hzwer部落格orz
因為每次我們找到了合法答案,子串起點∈[i-l,i-l+(l+r)%L],那麼這個區間中rank的最小值就是字典序最小起點,sa[min{rank}]即為答案起點
美到令人窒息的程式碼
#include<bits/stdc++.h> #define cls(x) memset(x,0,sizeof x) using namespace std; #define debug(x) cout<<#x<<"="<<x<<endl const int inf = 0x3f3f3f3f; const int maxn = 100009; const int Log = 17; int ft[maxn],n,ans,ord,ansl,ansr; char s[maxn]; struct ST { int mn[maxn][Log+1]; void clear(){memset(mn,0,sizeof mn);} void calc(int *a) { for(int i=1;i<=n;i++) mn[i][0]=a[i]; for(int i=1;i<=Log;i++) for(int j=1;j<=n-(1<<i>>1);j++) mn[j][i]=min(mn[j][i-1],mn[j+(1<<i>>1)][i-1]); } int query(int l,int r) { int ll=(r-l+1); ll=ft[ll]; return min(mn[l][ll],mn[r-(1<<ll)+1][ll]); } }rk; struct Suffix_Array { int sa[maxn],rank[maxn],t[maxn],t2[maxn],c[maxn],height[maxn]; ST mn; void init() { cls(sa);cls(rank);cls(height);cls(c); cls(t);cls(t2);mn.clear(); } void build() { int mr=30,*x=t,*y=t2; for(int i=1;i<=mr;i++) c[i]=0; for(int i=1;i<=n;i++) c[x[i]=s[i]-'a'+1]++; for(int i=1;i<=mr;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[x[i]]--]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(int i=n-k+1;i<=n;i++) y[++p]=i; for(int i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k; for(int i=1;i<=mr;i++) c[i]=0; for(int i=1;i<=n;i++) c[x[y[i]]]++; for(int i=1;i<=mr;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i]; swap(x,y); p=1;x[sa[1]]=1; for(int i=2;i<=n;i++) if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) x[sa[i]]=x[sa[i-1]]; else x[sa[i]]=++p; if(p>=n) break; mr=p; } for(int i=1;i<=n;i++) rank[sa[i]]=i; int h=0; for(int i=1;i<=n;i++) { if(rank[i]==1) h=0; else { int k=sa[rank[i]-1]; h--;if(h<0) h=0; while(s[i+h]==s[k+h]) h++; } height[rank[i]]=h; } mn.calc(height); } int lcp(int x,int y) { x=rank[x];y=rank[y]; if(x>y) swap(x,y);x++; return mn.query(x,y); } }a,b; void ClearLove(){ans=1;ord=inf;a.init();b.init();rk.clear();} void solve(int L) { for(int i=1;i+L<=n;i+=L) if(s[i]==s[i+L]) { int l=b.lcp((n-i+1)+1,(n-i-L+1)+1),r=a.lcp(i,i+L); int k=(l+r)/L+1; if(k>ans) ans=k,ord=inf; if(k==ans) { int t=rk.query(i-l,i-l+(l+r)%L); if(t<ord) { ord=t; ansl=a.sa[t];ansr=ansl+ans*L-1; } } } } int main() { for(int i=0;i<=Log;i++) ft[1<<i]=i; for(int i=1;i<=maxn-9;i++) if(!ft[i]) ft[i]=ft[i-1]; int cas=0; while(scanf("%s",s+1)) { if(s[1]=='#') break; ClearLove();n=strlen(s+1); cas++;printf("Case %d: ",cas); a.build();reverse(s+1,s+1+n);b.build(); rk.calc(a.rank);reverse(s+1,s+1+n); for(int i=1;i<=n;i++) if(a.rank[i]<ord) ord=a.rank[i],ansl=ansr=i; for(int i=1;i<=n;i++) solve(i); for(int i=ansl;i<=ansr;i++) putchar(s[i]); puts(""); } return 0; } //Hash_table 2017/1/22 //srO lct1999 Orz //srO hzwer Orz