您的位置:首页 > 其它

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}]即为答案起点

美到令人窒息的代码

#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 后缀数组 RMQ
相关文章推荐