• P4022 [CTSC2012]熟悉的文章


    题目

    P4022 [CTSC2012]熟悉的文章

    题目大意:多个文本串,多个匹配串,我们求(L)(L)指(匹配串中(≥L)长度的子串出现在文本串才为"熟悉",使得匹配串整个近似"熟悉")的最大值

    近似"熟悉":将匹配串分割,所有串总"熟悉"长度有(90\%)以上

    做法

    首先明确一点,(L_1<L_2),则(L_1)的熟悉程度(≥L_2)的熟悉程度

    比如文本串('adc'),匹配串('ac')(L=2)熟悉程度为(0\%)(L=1)熟悉程度为(100\%)

    故我们可以二分(L)然后去(dp),设数组(dp_i)为以(i)结尾前的熟悉长度

    则:(dp_i=max{dp_j+(i-j)}(jin [i-match_i,i-L])),其中(match_i)是以(i)结尾的后缀所能匹配的最长长度

    (i-match_i)(i-L)都是单调递增的,单调队列优化一下

    (O(nlogn))

    My complete code

    几个月前惨不忍睹的码风虽然现在依旧是,将就看吧

    #include<cstdio>
    #include<string>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    const LL maxn=400000;
    LL n,m,nod=1,last,Len;
    LL len[maxn],son[maxn][26],fail[maxn],val[maxn],dp[maxn];
    char s[maxn];
    inline void Insert(LL c){
        LL p=last,np=++nod;
        last=np;
        len[np]=len[p]+1;
        while(p&&!son[p][c]){
            son[p][c]=np;
            p=fail[p];
        }
        if(!p)
            fail[np]=1;
        else{
            LL q=son[p][c];
            if(len[q]==len[p]+1)
                fail[np]=q;
            else{
                LL nq=++nod;
                len[nq]=len[p]+1;
                memcpy(son[nq],son[q],sizeof(son[q]));
                fail[nq]=fail[q];
                fail[q]=fail[np]=nq;
                while(p&&son[p][c]==q){
                    son[p][c]=nq;
                    p=fail[p];
                }
            }
        }
    }
    inline void Match(){
        LL now=1,l=0;
        for(LL i=1;i<=Len;++i){
            LL c=s[i]-'0';
            while(now&&!son[now][c]){
                now=fail[now];
                l=len[now];
            }
            if(now){
                now=son[now][c];
                ++l;
            }else{
                now=1;
                l=0;
            }
            val[i]=l;
        }
    }
    inline bool check(LL L){
        LL head=1,tail=0;
        LL que[maxn];
        for(LL i=1;i<=L-1;++i)
            dp[i]=0;
        for(LL i=L;i<=Len;++i){
            while(head<=tail&&dp[que[tail]]-que[tail]<dp[i-L]-(i-L))
                --tail;
            que[++tail]=i-L;
            while(head<=tail&&que[head]<i-val[i])
                ++head;
            dp[i]=dp[i-1];
            if(head<=tail)
                dp[i]=max(dp[i],dp[que[head]]-que[head]+i);
        }
        return dp[Len]*10>=Len*9;
    }
    inline LL Solve(){
        LL l=1,r=Len,ans=0;
        Match();
        while(l<=r){
            LL mid=(l+r)>>1;
            if(check(mid)){
                ans=mid;
                l=mid+1;
            }else
                r=mid-1;
        }
        return ans;
    }
    int main(){
        scanf("%lld%lld",&n,&m);
        while(m--){
            scanf(" %s",s+1);
            Len=strlen(s+1);
            last=1;
            for(LL i=1;i<=Len;++i)
                Insert(s[i]-'0');
        }
        while(n--){
            scanf(" %s",s+1);
            Len=strlen(s+1);
            printf("%lld
    ",Solve());
        }
    }
    
  • 相关阅读:
    Delphi数据库处理
    delphi 递归的方法
    C#中StringBuilder用法以及和String的区别
    算法导论12.2节习题解答
    算法导论9.11习题解答(二叉树)
    算法导论10.15习题解答(deque实现源码)
    算法导论9.39习题解答(寻找中位数)
    算法导论84习题解答
    算法导论10.17习题解答(用两个队列实现一个栈)
    算法导论10.27习题解答(单链表逆转)
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10317388.html
Copyright © 2020-2023  润新知