bzoj4698Sdoi2008 Sandy的卡片 后缀数组+二分

来源:互联网 发布:java系统日工具 编辑:程序博客网 时间:2024/05/20 13:40

其实不是很难的一道题,但是被坑了很久= =。。。
首先他没有给出字符集所以我们要自己算出来。
然后,离散一下,这里的离散是把所有的数字变成他们之间的差(这个很显然但是不好想,可能是我有点sb想了半天才想到)
然后SA求出height以后二分判断的时候扫一遍看看连续LCP>=mid的是否有n个就可以了。

#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define inf 2000000000using namespace std;const int N=3e5+5;int n;int vis[1005];int b[N],c[N],d[N],height[N],sa[N],rank[N];int s[N];int mx=0,mn=inf,L=1,R=inf;int tot,l[N],r[N],a[1005][1005],id[N];inline void getsa(int n,int m){    fo(i,0,m)b[i]=0;    fo(i,1,n)b[s[i]]++;    fo(i,1,m)b[i]+=b[i-1];    fd(i,n,1)c[b[s[i]]--]=i;    int t=0;    fo(i,1,n)    {        if (s[c[i]]!=s[c[i-1]])t++;        rank[c[i]]=t;    }    int j=1;    while (j<=n)    {        fo(i,0,n)b[i]=0;        fo(i,1,n)b[rank[i+j]]++;        fo(i,1,n)b[i]+=b[i-1];        fd(i,n,1)c[b[rank[i+j]]--]=i;        fo(i,0,n)b[i]=0;        fo(i,1,n)b[rank[i]]++;        fo(i,1,n)b[i]+=b[i-1];        fd(i,n,1)d[b[rank[c[i]]]--]=c[i];        int t=0;        fo(i,1,n)        {            if (rank[d[i]]!=rank[d[i-1]]||            rank[d[i]]==rank[d[i-1]]&&rank[d[i]+j]!=rank[d[i-1]+j])t++;            c[d[i]]=t;        }        fo(i,1,n)rank[i]=c[i];        if (t==n)break;        j*=2;    }    fo(i,1,n)sa[rank[i]]=i;}inline void getheight(){    int k=0;    fo(i,1,tot)    {        if (k) k--;        int j=sa[rank[i]-1];        while (i+k<=tot&&j+k<=tot&&s[i+k]==s[j+k]) k++;        height[rank[i]]=k;    }}inline bool pd(int x){    int num=0;    fo(i,1,tot)    {        if (height[i]<x)        {            num=0;            memset(vis,0,sizeof(vis));        }        if (!vis[id[sa[i]]])        {            vis[id[sa[i]]]=1;            num++;        }        if (num==n)return 1;    }    return 0;}int main(){    scanf("%d",&n);    fo(i,1,n)    {        scanf("%d",&l[i]);        fo(j,1,l[i])        {            scanf("%d",&a[i][j]);            if (j!=1)mx=max(mx,a[i][j]-a[i][j-1]);         }        R=min(R,l[i]);    }    fo(i,1,n)    {        fo(j,2,l[i])        {            s[++tot]=a[i][j]-a[i][j-1];            id[tot]=i;        }        s[++tot]=++mx;    }    fo(i,1,tot)mn=min(s[i],mn);    fo(i,1,tot)    {        s[i]=s[i]-mn+1;        mx=max(mx,s[i]);    }    getsa(tot,mx);    getheight();    //printf("%d %d %d\n",mx,mn,tot);    int ans=1;    while (L<=R)    {        int mid=(L+R)>>1;        if (pd(mid))        {            ans=mid+1,L=mid+1;        }        else R=mid-1;    }    printf("%d\n",ans);}
原创粉丝点击