首页 > 技术文章 > [SDOI2008]Sandy的卡片

Mrsrz 2018-09-07 15:52 原文

题目大意:

给你n个串\(s_1\sim s_n\),要你在每个串中找一个长度为k的子串,满足任意\(1\leqslant i<k\),有\(s_1[i+1]-s_1[i]=s_2[i+1]-s_2[i]=\dots=s_n[i+1]-s_n[i]\)。问满足条件的k最大是多少。

解题思路:

相邻两个数差相等,我们先将原串进行差分。

然后首尾相连求后缀数组(中间用分隔符隔开)。

二分答案。对于答案t,考虑height数组中所有连续的,且大于等于t的子区间,若包含1~n所有串,则答案可行。

由于进行了差分,最后答案+1即可。

C++ Code:

#include<bits/stdc++.h>
const int NN=1200005;
inline int readint(){
    int c=getchar(),d=0,f=0;
    for(;!isdigit(c);c=getchar())f=c=='-';
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^'0');
    return f?-d:d;
}
int N,s[NN],n=0,a[1005],fg=30005,t1[NN],t2[NN],c[NN],rk[NN],height[NN],belong[NN],sa[NN];
bool vis[1005];
inline void sa_sort(){
    int*x=t1,*y=t2,m=60000;
    memset(c,0,sizeof c);
    for(int i=1;i<=n;++i)++c[x[i]=s[i]];
    for(int i=1;i<=m;++i)c[i]+=c[i-1];
    for(int i=n;i;--i)sa[c[x[i]]--]=i;
    for(int k=1;k<=n;k<<=1){
        int p=0;
        for(int i=n-k+1;i<=n;++i)y[++p]=i;
        for(int i=1;i<=n;++i)if(sa[i]>k)y[++p]=sa[i]-k;
        for(int i=0;i<=m;++i)c[i]=0;
        for(int i=1;i<=n;++i)++c[x[y[i]]];
        for(int i=1;i<=m;++i)c[i]+=c[i-1];
        for(int i=n;i;--i)sa[c[x[y[i]]]--]=y[i];
        int*tmp=x;x=y,y=tmp;
        x[sa[p=1]]=1;
        for(int i=2;i<=n;++i)
        x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p:++p;
        if(p==n)break;
        m=p;
    }
}
inline void get_height(){
    for(int i=1;i<=n;++i)rk[sa[i]]=i;
    for(int i=1,k=0;i<=n;++i)
    if(rk[i]!=1){
        if(k)--k;
        int j=sa[rk[i]-1];
        while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])++k;
        height[rk[i]]=k;
    }
}
inline bool check(int k){
    memset(vis,0,sizeof vis);
    int ok=1;
    vis[belong[sa[1]]]=1;
    for(int i=2;i<=n;++i){
        if(height[i]>=k){
            if(!vis[belong[sa[i]]]){
                vis[belong[sa[i]]]=1;
                if(++ok>=N)return 1;
            }
        }else{
            int j;
            for(j=i-1;j&&height[j]>=k;--j)
            vis[belong[sa[j]]]=0;
            vis[belong[sa[j]]]=0;
            vis[belong[sa[i]]]=1;
            ok=1;
        }
        if(!belong[sa[i]])break;
    }
    return 0;
}
int main(){
    N=readint();
    for(int i=1;i<=N;++i){
        int nn=readint();
        for(int j=0;j<nn;++j)a[j]=readint();
        for(int j=nn-1;j;--j)a[j]-=a[j-1];
        for(int j=1;j<nn;++j)s[++n]=a[j]+10001,belong[n]=i;
        s[++n]=fg++;
    }
    sa_sort();
    get_height();
    int l=1,r=1001,ans=0;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid))l=(ans=mid)+1;else
        r=mid-1;
    }
    printf("%d\n",ans+1);
    return 0;
}

推荐阅读