zoukankan      html  css  js  c++  java
  • BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]

    2806: [Ctsc2012]Cheat


    题意:

    多个主串和多个询问串,每次询问将询问串分成多个连续子串,如果一个子串长度>=L且在主串中出现过就是熟悉的

    如果熟悉的字符串长度>=询问串长的90%就是熟悉的文章;求成为熟悉的文章的最大的L


    主串建广义SAM然后二分L判断可行性

    使用DP判断L是否可行,一定要注意是长度不是数量,煞笔Candy?就看错题了

    len[i]表示i位置之前最大公共长度,和spoj LCS一样...

    f[i]表示前i个字符最长熟悉长度,f[i]=max{f[i-1],f[j]+j-i|i-len[i]<=j<=i-L},显然i-len[i]不严格递增,使用单调队列优化到O(n)

    DP注意:

    1.f[i-1]这个转移

    2.判断条件i-L<0说明没有转移;0也是一个转移!!但不能一开始先把0加入队列WA了好多次

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int N=1e6+5;
    typedef long long ll;
    int n,m;
    char s[N];
    struct node{
        int ch[2],par,val;
    }t[N];
    int sz=1,root=1,last=1;
    void extend(int c){
        int p=last,np=++sz;
        t[np].val=t[p].val+1;
        for(;p&&!t[p].ch[c];p=t[p].par) t[p].ch[c]=np;
        if(!p) t[np].par=root;
        else{
            int q=t[p].ch[c];
            if(t[q].val==t[p].val+1) t[np].par=q;
            else{
                int nq=++sz;
                t[nq]=t[q];t[nq].val=t[p].val+1;
                t[q].par=t[np].par=nq;
                for(;p&&t[p].ch[c]==q;p=t[p].par) t[p].ch[c]=nq;
            }
        }
        last=np;
    }
    int len[N],f[N];
    void getLen(){
        int u=root,sum=0;
        for(int i=1;i<=n;i++){
            int c=s[i]-'0';
            if(t[u].ch[c]) u=t[u].ch[c],sum++;
            else{
                while(u&&!t[u].ch[c]) u=t[u].par;
                if(!u) u=root,sum=0;
                else sum=t[u].val+1,u=t[u].ch[c];
            }
            len[i]=sum;//printf("len %d %d
    ",i,len[i]);
        }
    }
    int q[N],head,tail;
    bool check(int L){//printf("L %d
    ",L);
        head=1;tail=0;
        for(register int i=1;i<=n;i++){
            f[i]=f[i-1];
            if(i-L<0) continue;
            while(head<=tail&&f[q[tail]]-q[tail]<f[i-L]-i+L) tail--;
            q[++tail]=i-L;
            while(head<=tail&&q[head]<i-len[i]) head++;
            if(head<=tail) f[i]=max(f[i],f[q[head]]+i-q[head]);
            //printf("f %d %d
    ",i,f[i]);
        }
        //printf("f %d %d
    ",n,f[n]);
        return f[n]*10>=n*9;
    }
    void solve(){
        getLen();
        int l=0,r=n,ans=0;
        while(l<=r){
            int mid=(l&r)+((l^r)>>1);
            if(check(mid)) ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d
    ",ans);
    }
    int main(){
        freopen("in","r",stdin);
        scanf("%d%d",&m,&n);
        for(int i=1;i<=n;i++){
            scanf("%s",s+1);
            int len=strlen(s+1);
            last=root;
            for(int j=1;j<=len;j++) extend(s[j]-'0');
        }
        for(int i=1;i<=m;i++){
            scanf("%s",s+1);
            n=strlen(s+1);
            solve();
        }
    }
  • 相关阅读:
    Excel设置下拉选项的方法
    Codeforces Round #218 (Div. 2) (线段树区间处理)
    手动配置S2SH三大框架报错(一)
    一种H.264高清视频的无参考视频质量评价算法(基于QP和跳过宏块数)
    UIWebView的使用
    AFNetworkIng的简单使用
    虚线边框的实现
    iOS实现简单时钟效果
    hdu 3966 Aragorn's Story
    Count on a tree
  • 原文地址:https://www.cnblogs.com/candy99/p/6382172.html
Copyright © 2011-2022 走看看