zoukankan      html  css  js  c++  java
  • bzoj2806: [Ctsc2012]Cheat

    被hhn d飞a 一直不想(gan)做这题

    首先先把作文库插入SAM,两两间插个2(这里产生很多细节!空间要开到3,而且深度是要累计的)

    对于每个作文,先在SAM跑一遍,求出match数组,该数组表示以当前为结束点往前最长能被自动机识别的长度

    二分答案

    考虑DP,f[i]表示到第i个位置,最多能够识别多少字符

    那么明显f[i]=max(f[j]+i-j) 并且j>i-match[i]  因为f[j]已经搞好,对于j+1~i,都是能被匹配的

    然后j<i-L,就是题意限制了。

    这个DP是O(n^2)的啊,但是因为i-L单调可以用单调队列优化。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const double li=0.8999999999; 
    char ss[110000];
    
    struct SAM
    {
        int w[3],parent,L;
    }ch[1100000];int root,cnt,last;
    void add(int i,int dep)
    {
        int x=ss[i]-'0';
        int now=++cnt,p=last;
        ch[now].L=dep;
        
        while(p!=0&&ch[p].w[x]==0)ch[p].w[x]=now,p=ch[p].parent;
        if(p==0)ch[now].parent=root;
        else
        {
            int pre=ch[p].w[x];
            if(ch[pre].L==ch[p].L+1)ch[now].parent=pre;
            else
            {
                int npre=++cnt;
                ch[npre]=ch[pre];
                ch[npre].L=ch[p].L+1;
                
                ch[pre].parent=ch[now].parent=npre;
                while(p!=0&&ch[p].w[x]==pre)ch[p].w[x]=npre,p=ch[p].parent;
            }
        }
        last=now;
    }
    
    //---------------init-----------------------------
    
    int match[110000];
    void getmatch(int len)
    {
        int now=root,sum=0;
        for(int i=1;i<=len;i++)
        {
            int x=ss[i]-'0';
            if(ch[now].w[x]!=0) sum++, now=ch[now].w[x];
            else
            {
                while(now!=0&&ch[now].w[x]==0)now=ch[now].parent;
                if(now==0) sum=0, now=root;
                else sum=ch[now].L+1, now=ch[now].w[x];
            }
            match[i]=sum;
        }
    }
    
    int f[110000],list[110000];
    bool check(int mid,int len)
    {
        int head=1,tail=1;
        f[0]=0;list[1]=0;
        for(int i=1;i<=len;i++)
        {
            int u=i-mid;f[i]=f[i-1];
            if(u<0)continue;
            
            while(head<=tail&&f[list[tail]]+i-list[tail]<=f[u]+i-u)tail--;
            list[++tail]=u;
            while(head<=tail&&list[head]<i-match[i])head++;
            if(head<=tail)f[i]=max(f[i],f[list[head]]+i-list[head]);
        }
        if( (double(f[len]))/(double(len)) >=li)return true;
        return false;
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        root=cnt=last=1;
        int dep=0; 
        for(int i=1;i<=m;i++)
        {
            scanf("%s",ss+1);
            int len=strlen(ss+1);ss[++len]='2';
            for(int j=1;j<=len;j++)
            {
                dep++;
                add(j,dep);
            }
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%s",ss+1);int len=strlen(ss+1); 
            getmatch(len);
            int l=1,r=len,ans=0;
            while(l<=r)
            {
                int mid=(l+r)/2;
                if(check(mid,len)==true)
                {
                    l=mid+1;
                    ans=mid; 
                }
                else r=mid-1;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    递归
    作业 3月24日
    生成器
    迭代器
    解决python print 字符串 编码报错现象 unencode
    模式匹配迅速入手——ahocorasick第三方数据库的使用
    删除oracle部分数据
    html_获取参数
    ahocorasick从安装到使用
    Java 遍历map的四种方法
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8926692.html
Copyright © 2011-2022 走看看