zoukankan      html  css  js  c++  java
  • BZOJ2806:[CTSC2012]Cheat(广义SAM,二分,DP)

    Description

    Input

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

    Output

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

    Sample Input

    1 2
    10110
    000001110
    1011001100

    Sample Output

    4

    HINT

    输入文件不超过1100000字节

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

    Solution

    首先把广义$SAM$建出来,然后考虑对于一个询问,

    我们可以把这个作文放到$SAM$上跑,就可以求得这个字符串的每个位置向前延伸仍然可以匹配的最大长度,记为$Len[i]$。

    因为直接求答案不好求,所以我们二分一个答案$lim$

    剩下的就是$DP$了。$f[i]$表示到第$i$个位置最多能匹配多少,转移显然。

    $f[i]=max(f[i-1]),sum_{j=lim}^{len} f[i-j]+j$。 单调队列优化一下即可。

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define N (2200009)
     5 using namespace std;
     6 
     7 int n,m,len,Len[N],f[N],q[N];
     8 char s[N];
     9 
    10 struct SAM
    11 {
    12     int son[N][2],fa[N],step[N];
    13     int p,q,np,nq,last,cnt;
    14     SAM(){last=cnt=1;}
    15 
    16     void Insert(int x)
    17     {
    18         p=last; np=last=++cnt; step[np]=step[p]+1;
    19         while (p && !son[p][x]) son[p][x]=np,p=fa[p];
    20         if (!p) fa[np]=1;
    21         else
    22         {
    23             q=son[p][x];
    24             if (step[q]==step[p]+1) fa[np]=q;
    25             else
    26             {
    27                 nq=++cnt; step[nq]=step[p]+1;
    28                 memcpy(son[nq],son[q],sizeof(son[q]));
    29                 fa[nq]=fa[q]; fa[q]=fa[np]=nq;
    30                 while (son[p][x]==q) son[p][x]=nq,p=fa[p];
    31             }
    32         }
    33     }
    34     void Find(char s[])
    35     {
    36         int now=1,len=0;
    37         for (int i=0,l=strlen(s); i<l; ++i)
    38         {
    39             int c=s[i]-'0';
    40             if (son[now][c]) ++len,now=son[now][c];
    41             else
    42             {
    43                 while (now && !son[now][c]) now=fa[now];
    44                 if (!now) len=0,now=1;
    45                 else len=step[now]+1,now=son[now][c];
    46             }
    47             Len[i+1]=len;
    48         }
    49     }
    50 }SAM;
    51 
    52 bool check(int lim)
    53 {
    54     int head=1,tail=0,len=strlen(s);
    55     for (int i=1; i<=len; ++i)
    56     {
    57         f[i]=f[i-1];
    58         if (i-lim<0) continue;
    59         while (head<=tail && f[q[tail]]-q[tail]<=f[i-lim]-i+lim) --tail;
    60         q[++tail]=i-lim;
    61         while (head<=tail && q[head]<i-Len[i]) ++head;
    62         if (head<=tail) f[i]=max(f[i],f[q[head]]+i-q[head]);
    63     }
    64     return f[len]*10>=len*9;
    65 }
    66 
    67 int main()
    68 {
    69     scanf("%d%d",&n,&m);
    70     for (int i=1; i<=m; ++i,SAM.last=1)
    71     {
    72         scanf("%s",s);
    73         for (int j=0,l=strlen(s); j<l; ++j)
    74             SAM.Insert(s[j]-'0');
    75     }
    76     for (int i=1; i<=n; ++i)
    77     {
    78         scanf("%s",s);
    79         SAM.Find(s);
    80         int l=1,r=strlen(s),ans=0;
    81         while (l<=r)
    82         {
    83             int mid=(l+r)>>1;
    84             if (check(mid)) ans=mid,l=mid+1;
    85             else r=mid-1;
    86         }
    87         printf("%d
    ",ans);
    88     }
    89 }
  • 相关阅读:
    重构与模式:改善代码三部曲中的第三部
    将博客搬至CSDN
    管理之道(二十二)
    管理之道(二十一)
    管理之道(二十)
    管理之道(十九)
    管理之道(十八)
    管理之道(十七)
    管理之道(十六)
    管理之道(十五)
  • 原文地址:https://www.cnblogs.com/refun/p/10021310.html
Copyright © 2011-2022 走看看