您的位置:首页 > 其它

poj1743(后缀数组+二分)

2016-08-07 15:43 239 查看
不可重叠最长重复子串

后缀数组后,二分最长长度,在维护长度不小于mid时,判断是否有两个位置之间的差>mid,表示不重叠,由此更新l,r

方法:字符串处理常用二分+后缀数组常用分组

分组的本质就是这个组均包含长度为mid的子串,就是这个组的长度为mid的前缀都相同

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=20050;
const int inf=0x3f3f3f3f;
inline int read()
{
int ans,f=1;char ch;
while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0';
while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';
return ans*f;
}
int n,sa
,rank
,height
,s
,t1
,t2
,c
,p
;
void clear()
{
memset(p,0,sizeof(p));
memset(sa,0,sizeof(sa));
memset(rank,0,sizeof(rank));
memset(height,0,sizeof(height));
memset(s,0,sizeof(s));
memset(t1,0,sizeof(t1));
memset(t2,0,sizeof(t2));
}
void build_sa()
{
int m=200,*x=t1,*y=t2;
for (int i=0;i<m;i++) c[i]=0;
for (int i=0;i<n;i++) c[x[i]=s[i]]++;
for (int i=1;i<m;i++) c[i]+=c[i-1];
for (int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;

for (int k=1;k<=n;k<<=1)
{
int p=0;
for (int i=n-k;i<n;i++) y[p++]=i;
for (int i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k;

for (int i=0;i<m;i++) c[i]=0;
for (int i=0;i<n;i++) c[x[y[i]]]++;
for (int i=1;i<m;i++) c[i]+=c[i-1];
for (int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
x[sa[0]]=0;p=1;
for (int i=1;i<n;i++)
x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;
if (p>=n) break;
m=p;
}
}
void build_height()
{
int k=0;
for (int i=0;i<n;i++) rank[sa[i]]=i;
for (int i=0;i<n-1;i++)
{
if (k)k--;
int j=sa[rank[i]-1];
while (s[j+k]==s[i+k]) k++;
height[rank[i]]=k;
}
}
bool pan(int mid)
{
int mx,mi,h=inf;
for (int i=1;i<n;i++)
{
h=min(h,height[i]);
if (h<mid)
{
h=inf;
mx=mi=sa[i];
continue;
}
if (mx<sa[i]) mx=sa[i];
if (mi>sa[i]) mi=sa[i];
if (mx-mi>mid) return true;
}
return false;
}
void debug()
{
for (int i=1;i<n;i++)
{
for (int j=sa[i];j<n;j++) printf("%d ",s[j]);
printf("\n");
}
}
int main()
{
while ((n=read())!=0)
{
clear();
for (int i=0;i<n;i++) p[i]=read();
if (n==1) {printf("0\n");continue;}
n--;
for (int i=0;i<n;i++) s[i]=p[i+1]-p[i]+90;
s[n++]=0;
build_sa();
//debug();
build_height();
int ans=0,l=4,r=n,mid;
while (l<=r)
{
mid=(l+r)>>1;
if (pan(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans?ans+1:0);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: