http://poj.org/problem?id=3261
根据http://blog.csdn.net/taceo/article/details/9908545论文
由于数据比较大 先离散化
求出height数组
在二分字符串的长度求解 把height数组分组 看是否存在一组中 存在height[i]大于length k次的 然后进一步求解
#include<iostream>
#include<cstdio>
#include<string.h>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=20010;
int r[maxn];
int sa[maxn],wb[maxn], wa[maxn],wv[maxn], wt[maxn], rank[maxn],height[maxn];
int a[maxn],b[maxn],k,len;
int cmp(int *g,int a,int b,int l)
{
return (g[a]==g[b] && g[a+l]==g[b+l]); //这里是l
}
void da(int *r,int n,int m) //字符串从1到n
{
int i,j,p;
int *x=wa;
int *y=wb;
int *t;
for(i=0; i<m; i++) wt[i]=0;
for(i=1; i<=n; i++) wt[x[i]=r[i]]++;
for(i=1; i<m; i++) wt[i]+=wt[i-1];
for(i=n; i>=1; i--) sa[wt[x[i]]--]=i;
for(j=1,p=1; p<=n; j*=2,m=p)
{
for(p=1,i=n-j+1; i<=n; i++) y[p++]=i;
for(i=1; i<=n; i++) if(sa[i]>j) y[p++]=sa[i]-j;
for(i=1; i<=n; i++) wv[i]=x[y[i]];
for(i=0; i<m; i++) wt[i]=0;
for(i=1; i<=n; i++) wt[wv[i]]++;
for(i=1; i<m; i++) wt[i]+=wt[i-1];
for(i=n; i>=1; i--) sa[wt[wv[i]]--]=y[i];
for(t=x,x=y,y=t,p=2,x[sa[1]]=1,i=2; i<=n; i++)
x[sa[i]]=( cmp(y,sa[i-1],sa[i],j)?p-1:p++);
}
return ;
}
void Cal_height(int n) //求height数组
{
int i,j,k=1;
for(i=1; i<=n; height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++) ;
return ;
}
int cmp1(int x1,int y1)
{
return x1<y1;
}
int Query(int v)
{
int l=1,r=len;
while(l<=r)
{
int mid=(l+r)/2;
if(a[mid]==v) return mid;
if(v<a[mid]) r=mid-1;
else l=mid+1;
}
return -1;
}
bool Can(int length,int n)
{
int i;
for(i=2; i<=n; i++)
{
int c=0;
while(i<=n && height[i]>=length) //分组 height[i]大于length
{
c++;
i++;
}
if(c>=k-1) //且需要k次
return true;
}
return false;
}
int main()
{
int i,n,m;
while(scanf("%d %d",&n,&k)!=EOF)
{
for(i=1; i<=n; i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(a+1,a+n+1,cmp1); //离散化
len=1;
for(i=2; i<=n; i++)
{
while(i<=n && a[i]==a[i-1])
i++;
a[++len]=a[i];
}
for(i=1; i<=n; i++)
r[i]=Query(b[i]);
r[n+1]=0;
m=20010;
da(r,n,m);
for(i=1; i<=n; i++)
rank[sa[i]]=i;
Cal_height(n);
int l=0;
int r=n; //直接暴力二分 从字符串的长度入手
int ans=0;
while(l<=r)
{
int mid=(l+r)/2;
if( Can(mid,n)==true) //
{
if(mid>ans) ans=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}