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\n",ans);
113     }
114     return 0;
115 }

 

posted @ 2018-11-30 19:40  Unstoppable728  阅读(213)  评论(0编辑  收藏  举报