poj1745(后缀数组+二分)

来源:互联网 发布:朴素贝叶斯算法matlab 编辑:程序博客网 时间:2024/05/16 11:52

题目大意:求最长的不重叠重复字串的最大值

思路:二分最长的长度L,然后按照height>=L分组,可以得出每一个L都会在同一组内,而这组sa[i]max-sa[i]min>=L 则成立
这题输入的细节比较多需要注意(我会说我T了

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=20005,inf=1e9;int n,k,p,q=1;int a[N],v[N],h[N],sa[2][N],rk[2][N];void calsa(int sa[N],int rk[N],int SA[N],int RK[N]){    for(int i=1;i<=n;i++)v[rk[sa[i]]]=i;    for(int i=n;i;i--)        if(sa[i]>k)            SA[v[rk[sa[i]-k]]--]=sa[i]-k;    for(int i=n-k+1;i<=n;i++)SA[v[rk[i]]--]=i;    for(int i=1;i<=n;i++)        RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i-1]]!=rk[SA[i]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);}void getsa(){    memset(v,0,sizeof(v));    p=0,q=1;    for(int i=1;i<=n;i++)v[a[i]]++;    for(int i=1;i<=200;i++)v[i]+=v[i-1];    for(int i=1;i<=n;i++)        sa[p][v[a[i]]--]=i;    for(int i=1;i<=n;i++)        rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i-1]]!=a[sa[p][i]]);    for(k=1;k<n;k<<=1,swap(p,q))        calsa(sa[p],rk[p],sa[q],rk[q]);}void geth(){    k=0;    for(int i=1;i<=n;i++)        if(rk[p][i]==1)h[rk[p][i]]=0;        else         {            int j=sa[p][rk[p][i]-1];            while(a[i+k]==a[j+k])k++;            h[rk[p][i]]=k;if(k>0)k--;        }}bool check(int x){    int mn=sa[p][1],mx=sa[p][1];    for(int i=2;i<=n;i++)        if(h[i]<x)            mn=mx=sa[p][i];        else         {            mn=min(mn,sa[p][i]);            mx=max(mx,sa[p][i]);            if(mx-mn>=x)return 1;        }    return 0;}void solve(){    int l=0,r=n/2,ans;    while(l<=r)    {        int mid=(l+r)>>1;        if(check(mid))ans=mid,l=mid+1;        else r=mid-1;    }    if(ans<4)puts("0");    else printf("%d\n",ans+1);}int main(){    while(cin>>n&&n) {        fo(i,1,n) cin>>a[i];        fo(i,1,n-1) a[i]=a[i+1]-a[i]+100;        n--;        getsa();geth();        solve();    }    return 0;}   
原创粉丝点击