POJ-3693--后缀数组求字典序最小重复次数最多子串
2017-01-22 15:41
447 查看
摘自2009年国家集训队罗穗骞论文《后缀数组-处理字符串的有力工具》
因此我们只需处理出原串正反两个版本的后缀数组,然后用rmq问题的处理方法求LCP,我的处理方法是让关键点包含在r中,如果想包含在l中,只需把向前向后扩展的位置稍作处理&查询rank最小值的区间端点分别+1即可。
字典序最小的处理方法摘自hzwer博客orz
因为每次我们找到了合法答案,子串起点∈[i-l,i-l+(l+r)%L],那么这个区间中rank的最小值就是字典序最小起点,sa[min{rank}]即为答案起点
美到令人窒息的代码
因此我们只需处理出原串正反两个版本的后缀数组,然后用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
相关文章推荐
- POJ-3693-Maximum repetition substring(后缀数组-重复次数最多的连续重复子串)
- poj 3693 后缀数组 重复次数最多的连续重复子串
- POJ 3693 Maximum repetition substring 后缀数组求重复次数最多子串
- POJ 题目 3693 Maximum repetition substring(后缀数组+RMQ+枚举求最小字典序的重复次数最多的子串)
- POJ 3693 重复次数最多的连续重复子串 后缀数组
- POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)
- poj 3693 后缀数组求重复次数最多的连续重复子串
- poj 3693 后缀数组 重复次数最多的连续重复子串
- POJ 3693 重复次数最多的子串是什么?【后缀数组】
- poj 3693 后缀数组 重复次数最多的连续重复子串
- POJ 3693 Maximum repetition substring(后缀数组[重复次数最多的连续重复子串])
- 【后缀数组求重复次数最多的连续重复子串】SPOJ687 POJ3693
- poj 3693 Maximum repetition substring 重复次数最多的子串(若有多个 输出字典序最小的子串) 后缀数组 (DC3) (SA)
- POJ 3693 Maximum repetition substring(重复次数最多的连续子串 字典序最小)
- POJ 3693 后缀数组 重复次数最多的连续重复子串 倍增法以及D3法
- SPOJ REPEATS - Repeats(后缀数组[重复次数最多的连续重复子串])
- Repeats SPOJ (后缀数组,寻找一个重复次数最多的子串)
- UVA 题目11512 - GATTACA(后缀数组求出现次数最多的子串及重复次数)
- Poj 3693 & Hdu 2459 Maximum repetition substring (08合肥Online 后缀数组+RMQ 重复次数最多的连续重复子串)
- 连续重复次数最多的重复子串 hdu2459 poj 3693