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

    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%

    正解:二分+后缀自动机+$dp$+单调队列。

    这道题思路好妙啊,人蠢没办法。。

    首先我们可以发现这道题满足可二分性,于是我们直接二分答案,判断合法性就行了。

    二分出一个答案以后,我们可以知道,要满足条件,首先每组匹配的串长度必须$geq mid$。

    然后因为匹配的串的长度必须大于等于原串长的$90\%$,那么我们可以设一个$dp$状态。

    $f[i]$表示前$i$个字符,最多能匹配的长度是多少,可以知道我们只要满足$f[n]geq 0.9*n$就行了。

    那么转移就比较好想了,$f[i]=f[j]+i-j$,当$i-lenleq jleq i-mid$时成立。其中$len$为以当前字符为最后一个点的最大匹配长度。

    匹配字符串还没讲。。我们直接对给出的$m$个串做一个广义后缀自动机,然后找最大匹配就在自动机上跳$parent$链就行了。

    这个方程乍一看还是$O(n^{2})$的,但是我们可以发现转移方程只和$j$有关,那么我们可以用一个单调队列来优化转移。

    然后这道题我们就做完了。。$bzoj$终于刷到$400$题了。。

     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 #define N (2200010)
     6 
     7 using namespace std;
     8 
     9 int ch[N][2],fa[N],l[N],f[N],st[N],sum[N],n,m,la,tot,len;
    10 char s[N];
    11 
    12 il int gi(){
    13   RG int x=0,q=1; RG char ch=getchar();
    14   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    15   if (ch=='-') q=-1,ch=getchar();
    16   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    17   return q*x;
    18 }
    19 
    20 il void add(RG int c){
    21   RG int p=la,np=ch[p][c]; la=np;
    22   if (np && l[np]==l[p]+1) return;
    23   np=++tot,l[np]=l[p]+1,la=np;
    24   for (;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
    25   if (!p){ fa[np]=1; return; } RG int q=ch[p][c];
    26   if (l[q]==l[p]+1) fa[np]=q; else{
    27     RG int nq=++tot; l[nq]=l[p]+1;
    28     fa[nq]=fa[q],fa[q]=fa[np]=nq;
    29     memcpy(ch[nq],ch[q],sizeof(ch[q]));
    30     for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
    31   }
    32   return;
    33 }
    34 
    35 il void getlen(){
    36   RG int p=1,L=0;
    37   for (RG int i=1,c;i<=len;++i){
    38     c=s[i]-'0'; while (p && !ch[p][c]) p=fa[p];
    39     if (!p) p=1,L=0; else L=min(L,l[p])+1,p=ch[p][c]; sum[i]=L;
    40   }
    41   return;
    42 }
    43 
    44 il int check(RG int key){
    45   RG int h=1,t=0;
    46   for (RG int i=1;i<=len;++i){
    47     f[i]=f[i-1]; if (i<key) continue;
    48     while (h<=t && f[st[t]]-st[t]<=f[i-key]-i+key) --t;
    49     st[++t]=i-key; while (h<=t && st[h]<i-sum[i]) ++h;
    50     if (h<=t) f[i]=max(f[i],f[st[h]]-st[h]+i);
    51   }
    52   return f[len]*10>=len*9;
    53 }
    54 
    55 int main(){
    56 #ifndef ONLINE_JUDGE
    57   freopen("cheat.in","r",stdin);
    58   freopen("cheat.out","w",stdout);
    59 #endif
    60   n=gi(),m=gi(),tot=1;
    61   for (RG int i=1;i<=m;++i){
    62     scanf("%s",s+1),len=strlen(s+1),la=1;
    63     for (RG int j=1;j<=len;++j) add(s[j]-'0');
    64   }
    65   while (n--){
    66     scanf("%s",s+1),len=strlen(s+1),getlen();
    67     RG int l=0,r=len,mid,ans=0;
    68     while (l<=r) mid=(l+r)>>1,check(mid)?(ans=mid,l=mid+1):r=mid-1;
    69     printf("%d
    ",ans);
    70   }
    71   return 0;
    72 }
  • 相关阅读:
    Git-常用命令大全
    winform- 发现一个博客做用户自定义控件文章非常好的
    winform- 实现画圆角矩形
    webpack 0-1 配置 以及 (性能优化)
    前端学习资料网址收集整理
    直线参数方程的研究
    高中数学向量点乘的坐标证明的一点疑惑。
    微信小程序下载视频或者照片或者文件到本地相册中
    Webpack配置区分开发环境和生产环境
    gitHub 搜索技巧
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7632622.html
Copyright © 2011-2022 走看看