bzoj 4698: Sdoi2008 Sandy的卡片 (后缀数组+二分)

来源:互联网 发布:小公司网络组建 编辑:程序博客网 时间:2024/05/20 11:49

题目描述

传送门

题解

二分答案,判断是否有一段区间的height都大于当前答案,并且包含n个串中的每个串。

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define N 2000003using namespace std;int xx[N],yy[N],v[N],sa[N],rank[N],height[N],a[N];int n,m,tp,len,ti,p,vis[N],belong[N],*x,*y;int cmp(int i,int j,int l){    return y[i]==y[j]&&(i+l>len?-1:y[i+l])==(j+l>len?-1:y[j+l]);}void get_sa(){    m=tp; p=0; x=xx; y=yy;    for (int i=1;i<=len;i++) v[x[i]=a[i]]++;    for (int i=1;i<=m;i++) v[i]+=v[i-1];    for (int i=len;i>=1;i--) sa[v[x[i]]--]=i;    for (int k=1;k<=len;k<<=1) {        p=0;        for (int i=len-k+1;i<=len;i++) y[++p]=i;        for (int i=1;i<=len;i++)         if (sa[i]>k) y[++p]=sa[i]-k;        for (int i=1;i<=m;i++) v[i]=0;        for (int i=1;i<=len;i++) v[x[y[i]]]++;        for (int i=1;i<=m;i++) v[i]+=v[i-1];        for (int i=len;i>=1;i--) sa[v[x[y[i]]]--]=y[i];        swap(x,y); x[sa[1]]=1; p=2;        for (int i=2;i<=len;i++)         x[sa[i]]=cmp(sa[i],sa[i-1],k)?p-1:p++;        if (p>len) break;        m=p+1;    }    for (int i=1;i<=len;i++) rank[sa[i]]=i;    p=0;    for (int i=1;i<=len;i++) {        if (rank[i]==1) continue;        int j=sa[rank[i]-1];        while (i+p<=len&&j+p<=len&&a[i+p]==a[j+p]) p++;        height[rank[i]]=p;        p=max(0,p-1);    }}bool check(int k){    ti++; int cnt=0;    for (int i=1;i<=len;i++)      if (height[i]>=k) {        if (vis[belong[sa[i]]]!=ti&&belong[sa[i]]) cnt++;        vis[belong[sa[i]]]=ti;        if (cnt==n) return true;     }     else {        cnt=1; ti++;        vis[belong[sa[i]]]=ti;        if (!belong[sa[i]]) cnt=0;     }    return false;}int main(){    freopen("a.in","r",stdin);    freopen("my.out","w",stdout);    scanf("%d",&n);    tp=4021; len=0; int mx=0;    for (int i=1;i<=n;i++) {        int k,last; scanf("%d",&k);        mx=max(mx,k); scanf("%d",&last);        for (int j=2;j<=k;j++){            int x; scanf("%d",&x);            ++len; belong[len]=i; a[len]=x-last+2000;            last=x;        }        a[++len]=++tp;    }    get_sa();    int l=0; int r=mx; int ans=0;    while (l<=r) {        int mid=(l+r)/2;        if (check(mid)) ans=max(ans,mid),l=mid+1;        else r=mid-1;    }    printf("%d\n",ans+1);}
0 0
原创粉丝点击