zoukankan      html  css  js  c++  java
  • bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP

    2806: [Ctsc2012]Cheat

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 583  Solved: 330
    [Submit][Status][Discuss]

    Description

    Input

    第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库
    的行数
    接下来M行的01串,表示标准作文库
    接下来N行的01串,表示N篇作文

    Output

    N行,每行一个整数,表示这篇作文的Lo 值。

    Sample Input

    1 2
    10110
    000001110
    1011001100

    Sample Output

    4

    HINT

    输入文件不超过1100000字节

    注意:题目有改动,可识别的长度不小于90%即可,而不是大于90%

      先将作文库建后缀自动机,多篇文章可以通过在中间加入分隔符来完成。对于每组询问,预处理出每一个位置向前最多匹配多长g[]。

      二分答案len,dp[]表示匹配到当前位置的最多匹配数,对于i位置,dp[i]由一段通过len,与g确定出的区间[l,r]转移,本来用了一个线段树维护,但是由于时间复杂度O(n*log^2n),TLE了,观察发现[l,r]是单调的,故可直接用单调队列。

      网上一半题解过不了数据:1 1 1 1

      另外,对于0.9的问题确实说明了以后能用int就不要用double,实在不行要加eps。

      省选前最后一题了,真觉得时间过得太快了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define MAXN 4100000
    #define MAXT MAXN*4
    #define INF 0x3f3f3f3f
    #define lch (now<<1)
    #define rch (now<<1^1)
    #define smid ((l+r)>>1)
    char buf[MAXN];
    char *bufnow(buf);
    int len[MAXN];
    char *str[MAXN];
    char buf2[MAXN];
    char *bufnow2(buf2);
    struct sam_node
    {
            int nxt[3];
            int pnt,len;
            void Print()
            {
                    for (int i=0;i<3;i++)
                            printf("%d[%d] ",i,nxt[i]);
                    printf("
    ");
                    printf("Pnt:%d
    ",pnt);
            }
    }sam[MAXN];
    int tops=1;
    int last=1;
    void Add_item(int w)
    {
            int p=last;
            int np=++tops;
            sam[np].len=sam[p].len+1;
            while (p && !sam[p].nxt[w])
                    sam[p].nxt[w]=np,p=sam[p].pnt;
            if (!p)
            {
                    last=np;
                    sam[np].pnt=1;
            }else
            {
                    int q=sam[p].nxt[w];
                    if (sam[p].len+1==sam[q].len)
                    {
                            sam[np].pnt=q;
                    }else
                    {
                            int nq=++tops;
                            sam[nq]=sam[q];
                            sam[nq].len=sam[p].len+1;
                            sam[nq].pnt=sam[q].pnt;
                            sam[q].pnt=nq;
                            sam[np].pnt=nq;
                            while (p && sam[p].nxt[w]==q)
                            {
                                    sam[p].nxt[w]=nq;
                                    p=sam[p].pnt;
                            }
                    }
            }
            last=np;
    }
    int g[MAXN];
    int dp[MAXN];
    int seq[MAXN];
    
    int main()
    {
            freopen("input.txt","r",stdin);
            int n,m;
            int x,y;
            scanf("%d%d
    ",&n,&m);
            for (int i=0;i<m;i++)
            {
                    scanf("%s
    ",bufnow2);
                    bufnow2+=strlen(bufnow2);
                    *(bufnow2++)='2';
            }
            for (int i=0;i<n;i++)
            {
                    scanf("%s
    ",bufnow);
                    str[i]=bufnow;
                    bufnow+=len[i]=strlen(bufnow);
                    bufnow++;
            }
            for (char *i=buf2;i!=bufnow2;i++)
            {
                    Add_item(*i-'0');
            }
            for (int i=1;i<=tops;i++)
            {
            //        printf("SAM<%d>:
    ",i);
            //        sam[i].Print();
            }
            for (int i=0;i<n;i++)
            {
                    int now=1;
                    int clen=0;
                    for (int j=0;j<len[i];j++)
                    {
                            int w=str[i][j]-'0';
                            if (sam[now].nxt[w])
                            {
                                    now=sam[now].nxt[w];
                                    clen++;
                            }else
                            {
                                    while (now && !sam[now].nxt[w])
                                            now=sam[now].pnt;
                                    if (!now)
                                    {
                                            now=1;
                                            clen=0;
                                    }else
                                    {
                                            clen=sam[now].len+1;
                                            now=sam[now].nxt[w];
                                    }
                            }
                            g[j]=clen;
                //            printf("%d
    ",clen);
                    }
                    for (int j=len[i];j>=1;j--)
                            g[j]=g[j-1];
                    g[0]=0;
                    int l=0,r=len[i]+1;
                    int mid;
                    int head,tail=0;
                    int ny;
                    while (l+1<r)
                    {
                            mid=(l+r)>>1;
                            int t;
                            for (int j=1;j<=len[i];j++)
                                    dp[j]=-INF;
                            dp[0]=0;
                            head=0,tail=-1;
                            ny=0;
                            for (int j=1;j<=len[i];j++)
                            {
                                    x=j-g[j];
                                    y=j-mid;
                                    while (ny<=y)
                                    {
                                            while (head<=tail && dp[seq[tail]]<=dp[ny])
                                                    tail--;
                                            seq[++tail]=ny++;
                                    }
                                    while (head<=tail && seq[head]<x)
                                            head++;
                                    dp[j]=dp[j-1]+(j-1);
                                    if (head<=tail)
                                            dp[j]=max(dp[j],dp[seq[head]]+j);
                                    dp[j]-=j;
                            }
                            t=dp[len[i]]+len[i];
                            if (t*10>=len[i]*9)
                                    l=mid;
                            else
                                    r=mid;
                    }
                    printf("%d
    ",l);
            }
    }
  • 相关阅读:
    帝国 标签模板 使用程序代码 去除html标记 并 截取字符串
    iis6 伪静态 iis配置方法 【图解】
    您来自的链接不存在 帝国CMS
    帝国cms Warning: Cannot modify header information headers already sent by...错误【解决方法】
    .fr域名注册 51元注册.fr域名
    帝国网站管理系统 恢复栏目目录 建立目录不成功!请检查目录权限 Godaddy Windows 主机
    星外虚拟主机管理平台 开通数据库 出现Microsoft OLE DB Provider for SQL Server 错误 '8004' 从字符串向 datetime 转换失败
    ASP.NET 自定义控件学习研究
    CSS层叠样式表之CSS解析机制的优先级
    ASP.NET程序员工作面试网络收藏夹
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4433683.html
Copyright © 2011-2022 走看看