zoukankan      html  css  js  c++  java
  • 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)

    2806: [Ctsc2012]Cheat

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 1262  Solved: 643

    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%

    Source

    【分析】

      显然可以二分。

      然后就是判断。

      先用SAM找到i最长向左可以匹配的位置l,决策区间就是[i-l,i-lim],思考一下发现这个决策区间是不断向右移动的,就是类似滑动窗口?这个就可以用单调队列了。

      即f[i]=max{f[i-1],f[j]+j-i|i-l<=j<=i-lim}

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 using namespace std;
      7 #define Maxn 2500010
      8 
      9 int mymax(int x,int y) {return x>y?x:y;}
     10 
     11 struct node
     12 {
     13     int son[4],pre,step;
     14 }t[Maxn*2];
     15 
     16 struct sam
     17 {
     18     int tot,last;
     19     void extend(int k)
     20     {
     21         int np=++tot,p=last;
     22         t[np].step=t[p].step+1;
     23         while(p&&!t[p].son[k])
     24         {
     25             t[p].son[k]=np;
     26             p=t[p].pre;
     27         }
     28         if(!p) t[np].pre=1;
     29         else
     30         {
     31             int q=t[p].son[k];
     32             if(t[q].step==t[p].step+1) t[np].pre=q;
     33             else
     34             {
     35                 int nq=++tot;
     36                 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son));
     37                 t[nq].step=t[p].step+1;
     38                 t[nq].pre=t[q].pre;
     39                 t[q].pre=t[np].pre=nq;
     40                 while(p&&t[p].son[k]==q)
     41                 {
     42                     t[p].son[k]=nq;
     43                     p=t[p].pre;
     44                 }
     45             }
     46         }
     47         last=np;
     48     }
     49 }sam;
     50 
     51 char s[Maxn];
     52 
     53 int q[Maxn*2];
     54 int f[Maxn];
     55 bool check(int x,int ll)
     56 {
     57     int l=1,r=1;
     58     int nw=1,sm=0;
     59     for(int i=1;i<=ll;i++) f[i]=0;
     60     q[1]=0;
     61     for(int i=1;i<=ll;i++)
     62     {
     63         f[i]=f[i-1];
     64         int ind=s[i]-'0';
     65         while(nw&&!t[nw].son[ind]) nw=t[nw].pre,sm=t[nw].step;
     66         if(t[nw].son[ind]) nw=t[nw].son[ind],sm++;
     67         else {nw=1;sm=0;continue;}
     68         while(i-x>=0&&l<=r&&f[i-x]-(i-x)>f[q[r]]-(q[r])) r--;
     69         if(i-x>=0) q[++r]=i-x;
     70         while(l<=r&&(q[l]<i-sm||q[l]>i-x)) l++;
     71         if(l<=r) f[i]=mymax(f[i],f[q[l]]+i-q[l]);
     72     }
     73     return f[ll]*10>=ll*9;
     74 }
     75 
     76 int main()
     77 {
     78     int n,m;
     79     scanf("%d%d",&n,&m);
     80     sam.tot=sam.last=1;
     81     for(int i=1;i<=m;i++)
     82     {
     83         scanf("%s",s);
     84         int ll=strlen(s);
     85         for(int j=0;j<ll;j++) sam.extend(s[j]-'0');
     86         // sam.extend(2);
     87         sam.last=1;
     88     }
     89     for(int i=1;i<=n;i++)
     90     {
     91         scanf("%s",s+1);
     92         int ll=strlen(s+1);
     93         int l=0,r=ll;
     94         while(l<r)
     95         {
     96             int mid=(l+r+1)>>1;
     97             if(check(mid,ll)) l=mid;
     98             else r=mid-1;
     99         }
    100         printf("%d
    ",l);
    101     }
    102     return 0;
    103 }
    View Code

    【打的是广义SAM?

    2017-04-18 12:55:48

  • 相关阅读:
    文件夹无法删除解决方案
    常用Web Service汇总(天气预报、时刻表等)
    浏览器兼容手册
    如何在word2007下右键添加“新建Word 2003 文档”
    Centos7上实现不同网段的服务器文件共享
    ubuntu安装界面 会出现不完整情况
    Centos7搭建dhcp服务器
    Centos7上搭建ftp服务器
    Centos7上配置网络和本地yum方法
    浅谈网络流
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6727219.html
Copyright © 2011-2022 走看看