您的位置:首页 > 其它

POJ 3261 浅谈后缀数组HEIGHT数组的实际应用

2017-07-31 09:41 633 查看


世界真的很大

后缀数组是个神奇东西,应用也挺多的

后缀排名这个东西很有用

这又是一道奶牛题

POJ昨天卡了害得我测了好久

看题先:

description:

给定一个长为n(1≤n≤105 )的字符串,求其最长的至少出现了k次的
可重叠子串长度。


input

第一行两个整数n,k,接下来n个整数表示序列(字符串)


output

一个整数表示答案


看到求最长什么的应该想到二分,再考虑一下是不是具有二分的性质。

如果一个串出现了k次,那么长度比其小的串肯定至少出现了k次,这是显然的

那么就可以二分了,二分一个长度,每次check看有没有这个长度的字串出现了k次及以上

考虑怎么check,后缀数组中的后缀排名,如果几个后缀有一部分公共前缀,那么在后缀排名上他们一定是挨在一起的,因为后缀排名比较的是字典序,由于这几个后缀前几个字符都是相同的,所以字典序上他们必然是挨在一起的。

我们可以利用这个性质,把后缀排名里面,挨在一起的,有公共前缀长度大于二分的值的,分为一组,这一组里满足有长度大于二分值的公共字串,再检查组内是不是有超过k个后缀,就是这个公共字串有没有出现大于等于k次

完整代码:

#include<stdio.h>
#include<algorithm>
using namespace std;

int n,k,big=0;
int wa[100010],wb[100010],wv[100010],ws[100010];
int rank[100010],height[100010];
int sa[100010],r[100010];

bool cmp(int *r,int a,int b,int l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}

void calheight(int *r,int *sa,int n)
{
int k=0,j;
for(int i=1;i<=n;i++)
rank[sa[i]]=i;
for(int i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}

void da(int *r,int *sa,int n,int m)
{
int *x=wa,*y=wb,*t;
for(int i=0;i<m;i++) ws[i]=0;
for(int i=0;i<n;i++) ws[x[i]=r[i]]++;
for(int i=1;i<m;i++) ws[i]+=ws[i-1];
for(int i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(int p=1,j=1;p<n;j<<=1,m=p)
{
p=0;
for(int i=n-j;i<n;i++) y[p++]=i;
for(int i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(int i=0;i<n;i++) wv[i]=x[y[i]];
for(int i=0;i<m;i++) ws[i]=0;
for(int i=0;i<n;i++) ws[wv[i]]++;
for(int i=1;i<m;i++) ws[i]+=ws[i-1];
for(int i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
int i;
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]= cmp(y,sa[i-1],sa[i],j) ? p-1 : p++;
}
}

bool check(int mid)
{
int tmp=0;
for(int i=2;i<=n;i++)
{
if(height[i]>=mid)
tmp++;
if(tmp>=k) return 1;
if(height[i]<mid)
tmp=1;
}
return false ;
}

int main()
{
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
scanf("%d",&r[i]),big=max(big,r[i]);
da(r,sa,n+1,big+1);
calheight(r,sa,n);
int lf=1,rg=n,ans=0;
while(lf<=rg)
{
int mid=(lf+rg)>>1;
if(check(mid))
ans=mid,lf=mid+1;
else
rg=mid-1;
}
printf("%d\n",ans);
return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/


嗯,就是这样
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: