• 洛谷P4022 [CTSC2012]熟悉的文章 后缀自动机+二分+单调队列优化dp


    洛谷P4022 [CTSC2012]熟悉的文章

    题意

    (m)(01)(s_1,s_2,dots,s_n)(n)次询问,每次询问给出一个(01)(x),问是否存在一种分割方式将(x)分割成若干个子串使这些子串中长度大于等于(L)的且是(s_1,s_2,dots,s_n)中任意一个的子串的总长度大于等于(|x|cdot 90\%),问(L)最大为多少,若不存在输出(0)

    分析

    将这(m)个串用一个没出现过的字符连接起来建后缀自动机,二分(L)(check)就是对于(x)的每个前缀在自动机上匹配一个最长的后缀,设这个匹配长度为(l),若(l>=L),则有(dp[i]=max{dp[k]+i-k|kin [i-l,i-L]}),考虑优化,要找到区间([i-l,i-L])(dp[k]+i-k)的最大值然后转移,由于(i)是固定的,且对于每个前缀其区间左右端点是单调不减的,于是我们可以用单调队列来维护区间(dp[k]-k)的最大值,然后转移即可,最后判断(dp[n]cdot 10>=ncdot 9)来移动二分区间迭代找到答案。

    Code

    #include<bits/stdc++.h>
    #define rep(i,x,n) for(int i=x;i<=n;i++)
    #define per(i,n,x) for(int i=n;i>=x;i--)
    #define sz(a) int(a.size())
    #define rson mid+1,r,p<<1|1
    #define pii pair<int,int>
    #define lson l,mid,p<<1
    #define ll long long
    #define pb push_back
    #define mp make_pair
    #define se second
    #define fi first
    using namespace std;
    const double eps=1e-8;
    const int mod=1e9+7;
    const int N=3e6+10;
    const int M=1e6+10;
    const ll inf=1e18;
    int T,n,m;
    char s[N];
    int q[N];
    struct SAM{
        int last,cnt;int ch[N][3],fa[N],len[N];
        int dp[N];
        int newnode(){
            ++cnt;
            return cnt;
        }
        void insert(int c){
            int p=last,np=newnode();last=np;len[np]=len[p]+1;
            for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
            if(!p) fa[np]=1;
            else {
                int q=ch[p][c];
                if(len[q]==len[p]+1) fa[np]=q;
                else{
                    int nq=newnode();len[nq]=len[p]+1;
                    memcpy(ch[nq],ch[q],sizeof ch[q]);
                    fa[nq]=fa[q],fa[q]=fa[np]=nq;
                    for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
                }
            }
        }
        void init(){
            last=cnt=1;
        }
        bool solve(int L){
            int ln=strlen(s+1);
            rep(i,1,ln) dp[i]=0;
            int u=1,l=0;
            int dl=0,dr=-1;
            for(int i=1;i<=ln;i++){
                int j=i-L,c=s[i]-'0';
                if(j>=0){
                    while(dl<=dr&&dp[j]-j>dp[q[dr]]-q[dr]) --dr;
                    q[++dr]=j;
                }
                while(!ch[u][c]&&u!=1) u=fa[u],l=len[u];
                if(ch[u][c]) u=ch[u][c],l++;
                if(l>=L){
                    while(dl<=dr&&q[dl]<i-l) ++dl;
                    dp[i]=max(dp[i-1],dp[q[dl]]+i-q[dl]);
                }else dp[i]=dp[i-1];
            }
            return dp[ln]*10>=ln*9;
        }
    }sam;
    int main(){
        scanf("%d%d",&n,&m);
        sam.init();
        rep(i,1,m){
            scanf("%s",s+1);
            int len=strlen(s+1);
            for(int j=1;j<=len;j++) sam.insert(s[j]-'0');
            sam.insert(2);
        }
        rep(i,1,n){
            scanf("%s",s+1);
            int l=1,r=2000000;
            while(l<=r){
                int mid=l+r>>1;
                if(sam.solve(mid)) l=mid+1;
                else r=mid-1;
            }
            printf("%d
    ",r);
        }
        return 0;
    }
    
  • 相关阅读:
    ZOJ 1450
    HDU 3932
    POJ 3348
    POJ 1873
    POJ 1228
    POJ 2007
    POJ 1113
    POJ 1696
    POJ 1329
    HDU 3432
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13934218.html
Copyright © 2020-2023  润新知