洛咕 P2463 [SDOI2008]Sandy的卡片

哈希水过。

首先这是一段delta相同的序列,按照套路差分一下,b[i]=a[i]-a[i-1],然后就是这些序列的最长公共子段

由于数据范围很小,就可以二分,枚举第一个序列的子段然后每个子序列暴力check,跑得飞快。

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il int gi(){
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,M[1001],A[1001][102];
ll Hash1[1001][102],Base1[102],Mod1=998244853;
ll Hash2[1001][102],Base2[102],Mod2=1000000009;
il std::pair<ll,ll> Query(int x,int l,int r){
    return
        std::make_pair(
            (Hash1[x][r]-Hash1[x][l-1]+Mod1)*Base1[101-r]%Mod1,
            (Hash2[x][r]-Hash2[x][l-1]+Mod2)*Base2[101-r]%Mod2
        );
}
il bool check(int mid){
    for(int l=1;l+mid-1<=M[1];++l){
        std::pair<ll,ll>s=Query(1,l,l+mid-1);
        for(int i=2;i<=n;++i){
            bool flg=0;
            for(int j=1;j+mid-1<=M[i];++j)
                if(Query(i,j,j+mid-1)==s)
                    {flg=1;break;}
            if(!flg)goto GG;
        }
        return 1;
      GG:;
    }
    return 0;
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("2463.in","r",stdin);
    freopen("2463.out","w",stdout);
#endif
    n=gi();
    int l=0,r=1e9,mid;
    Base1[0]=1;for(int i=1;i<=101;++i)Base1[i]=Base1[i-1]*19260817%Mod1;
    Base2[0]=1;for(int i=1;i<=101;++i)Base2[i]=Base2[i-1]*23333%Mod2;
    for(int i=1;i<=n;++i){
        M[i]=gi();r=std::min(r,M[i]-1);
        for(int j=1;j<=M[i];++j)A[i][j]=gi();
        for(int j=M[i];j>1;--j)A[i][j]-=A[i][j-1];
        for(int j=1;j<=M[i];++j)Hash1[i][j]=(Hash1[i][j-1]+A[i][j]*Base1[j]%Mod1+Mod1)%Mod1;
        for(int j=1;j<=M[i];++j)Hash2[i][j]=(Hash2[i][j-1]+A[i][j]*Base2[j]%Mod2+Mod2)%Mod2;
    }
    while(l<r){
        mid=(l+r)>>1;
        if(check(mid+1))l=mid+1;
        else r=mid;
    }
    printf("%d\n",l+1);
    return 0;
}
posted @ 2018-10-17 15:28  菜狗xzz  阅读(201)  评论(0编辑  收藏  举报