• BZOJ2806: [Ctsc2012]Cheat(广义后缀自动机,单调队列优化Dp)


    Description

    Input

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

    Output

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

    Sample Input

    1 2
    10110
    000001110
    1011001100

    Sample Output

    4

    解题思路:

    L0值具有单调性。

    L0值为0时,一定有匹配,为1时只需要考虑字符集,为2时要考虑前后顺序,所以具有单调性,L0越小匹配长度越大,那么可以二分。

    这道题要求不能覆盖,所以不能使用简单的Dp来解决,但也很明显,得知一个字符串某一位为结尾时最长匹配长度是很有用的QAQ

    所以设f[i]为以文本串i结尾,最长可识别子串的长度,那么startpos就是i-f[i],设Dp[i]表示匹配到i最长(可以不连续,但不小于L0)的最大匹配长度。

    为了实现可不连续,Dp[i]初值为Dp[i-1],所以Dp[i]的转移方程就是Dp[i]=max(Dp[i-1],max({Dp[j]+i-j|i-j>=L0}))

    转移是O(n2)的过不了,可以将Dp[j]-j与i分离将Dp[j]-j用单调队列维护,就是O(n)的了^_^

    代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 struct sant{
      5     int tranc[26];
      6     int len;
      7     int pre;
      8 }s[2100000];
      9 int siz;
     10 int fin;
     11 int n,m;
     12 char tmp[2100000];
     13 int maxl[2100000];
     14 int dp[3000000];
     15 int x[2000000];
     16 void Insert(int c)
     17 {
     18     int nwp,nwq,lsp,lsq;
     19     nwp=++siz;
     20     s[nwp].len=s[fin].len+1;
     21     for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)
     22         s[lsp].tranc[c]=nwp;
     23     if(!lsp)
     24         s[nwp].pre=1;
     25     else{
     26         lsq=s[lsp].tranc[c];
     27         if(s[lsq].len==s[lsp].len+1)
     28             s[nwp].pre=lsq;
     29         else{
     30             nwq=++siz;
     31             s[nwq]=s[lsq];
     32             s[nwq].len=s[lsp].len+1;
     33             s[nwp].pre=s[lsq].pre=nwq;
     34             while(s[lsp].tranc[c]==lsq)
     35             {
     36                 s[lsp].tranc[c]=nwq;
     37                 lsp=s[lsp].pre;
     38             }
     39         }
     40     }
     41     fin=nwp;
     42     return ;
     43 }
     44 bool can(int L0,int len)
     45 {
     46     dp[0]=0;
     47     int t=0,h=1;
     48     for(int i=1;i<=len;i++)
     49     {
     50         dp[i]=dp[i-1];
     51         if(i<L0)
     52             continue;
     53         while(t>=h&&dp[x[t]]-x[t]<=dp[i-L0]-i+L0)t--;
     54         x[++t]=i-L0;
     55         while(t>=h&&x[h]<i-maxl[i])h++;
     56         if(t>=h)
     57             dp[i]=std::max(dp[x[h]]+i-x[h],dp[i]);
     58     }
     59     return 10*dp[len]>=9*len;
     60 }
     61 int main()
     62 {
     63     fin=++siz;
     64     scanf("%d%d",&n,&m);
     65     for(int i=1;i<=m;i++)
     66     {
     67         scanf("%s",tmp+1);
     68         int len=strlen(tmp+1);
     69         fin=1;
     70         for(int j=1;j<=len;j++)
     71             Insert(tmp[j]-'0');
     72     }
     73     while(n--)
     74     {
     75         scanf("%s",tmp+1);
     76         int len=strlen(tmp+1);
     77         int root=1;
     78         int mxl=0;
     79         for(int i=1;i<=len;i++)
     80         {
     81             int c=tmp[i]-'0';
     82             if(s[root].tranc[c])
     83             {
     84                 root=s[root].tranc[c];
     85                 mxl++;
     86             }else{
     87                 while(!s[root].tranc[c])
     88                     root=s[root].pre;
     89                 if(!root)
     90                 {
     91                     root=1;
     92                     mxl=0;
     93                 }else{
     94                     mxl=s[root].len+1;
     95                     root=s[root].tranc[c];
     96                 }
     97             }
     98             maxl[i]=mxl;
     99         }
    100         int ans=0;
    101         int l=0,r=len;
    102         while(l<=r)
    103         {
    104             int mid=(l+r)>>1;
    105             if(can(mid,len))
    106             {
    107                 ans=mid;
    108                 l=mid+1;
    109             }else
    110                 r=mid-1;
    111         }
    112         printf("%d
    ",ans);
    113     }
    114     return 0;
    115 }
  • 相关阅读:
    Ui——创建视图的方法及过程
    iOS设计模式----原型模式
    浅谈OC中排序的方法
    Solid Dominoes Tilings (轮廓线dp打表 + 容器)
    Shell Necklace (dp递推改cdq分治 + fft)
    Rigid Frameworks (画图二分图规律 + DP + 数学组合容斥)
    PowMod (欧拉推式子 + 指数循环节)
    Necklace (全排列 + 匈牙利)
    GCD (RMQ + 二分)
    Game (思维)
  • 原文地址:https://www.cnblogs.com/blog-Dr-J/p/10046126.html
Copyright © 2020-2023  润新知