POJ 1743 Musical Theme 后缀数组

来源:互联网 发布:淘宝上有正品蜘蛛刀吗 编辑:程序博客网 时间:2024/05/21 08:51

题意:链接

方法:后缀数组

解析:

这道题的话,我们只需要差分一下即可。现在问题就转化成求两个相同的子序列并且不相交。

直接用后缀数组求出来height数组之后二分答案即可。

但是注意一个问题,我们差分之后,如果寻找到的序列长度为4的话,实际上是5个数。

所以有一个加1的问题需要注意。

另外,题里有个要求..长度小于5输出0…这好坑啊= =!

代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 20010using namespace std;int n,a[N];int sa[N],rnk[N],height[N],t0[N],t1[N],cnt[210];void getsa(int m){    int *x=t0,*y=t1;    for(int i=0;i<m;i++)cnt[i]=0;    for(int i=0;i<n;i++)cnt[x[i]=a[i]]++;    for(int i=1;i<m;i++)cnt[i]+=cnt[i-1];    for(int i=n-1;i>=0;i--)sa[--cnt[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++)cnt[i]=0;        for(int i=0;i<n;i++)cnt[x[y[i]]]++;        for(int i=1;i<m;i++)cnt[i]+=cnt[i-1];        for(int i=n-1;i>=0;i--)sa[--cnt[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]]&&sa[i]+k<n&&sa[i-1]+k<n&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;        if(p==n)break;        m=p;     }}void getheight(){    int k=0;    for(int i=0;i<n;i++)rnk[sa[i]]=i;    for(int i=0;i<n;i++)    {        if(k!=0)k--;        if(!rnk[i])continue;        int j=sa[rnk[i]-1];        while(a[i+k]==a[j+k])k++;        height[rnk[i]]=k;    }}int check(int x){    int la=0;    for(int i=1;i<=n;i++)    {        if(height[i]<x||i==n)        {            int mi=0x3f3f3f3f,ma=-1;            for(int j=la;j<i;j++)            {                mi=min(mi,sa[j]);                ma=max(ma,sa[j]);             }            if(ma-mi>x)return 1;            la=i;        }    }    return 0;}int main(){    while(scanf("%d",&n)&&n!=0)    {        for(int i=0;i<n;i++)scanf("%d",&a[i]);        for(int i=0;i<n-1;i++)            a[i]=a[i+1]-a[i];        for(int i=0;i<n;i++)a[i]+=88;        a[--n]=0;         getsa(200);        getheight();        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;        }        if(ans>=4)            printf("%d\n",ans+1);        else puts("0");    }}
0 0
原创粉丝点击