http://poj.org/problem?id=3261
题意就是给你一个数字串,让你求一个串中重复至少出现k次的最长重叠子串。
做法:用后缀数组也很简单,直接对他求后缀数组,然后二分答案,就可以了,验证的时候就是验证是否有连续的k-1个height数组的值都大于等于mid,和我以前写的几道题都差不多,但不过注意这道题数据中有0,所以加加一下。
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
const int N=1000010;
int s[N],x[N],y[N],n,m;
int c[N],sa[N],height[N],rk[N];
void Suffix()
{
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);
p=1;x[sa[0]]=0;
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 geth()
{
for(int i=0;i<n;i++) rk[sa[i]]=i;
for(int i=0,k=0;i<n;i++)
{
if(rk[i])
{
if(k) --k;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k]) k++;
height[rk[i]]=k;
}
}
}
int k;
int check(int x)
{
int cnt=0;
for(int i=1;i<n;i++)
{
if(height[i]>=x) cnt++;
else cnt=0;
if(cnt>=k-1)
return 1;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&k);
int mx=0,x;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
s[i]=x+1;
mx=max(mx,s[i]);
}
s[n++]=0;
m=mx+1;
Suffix();
geth();
int l=0,r=n,ans;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
printf("%d\n",ans);
return 0;
}