Description
Input
第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库
的行数
接下来M行的01串,表示标准作文库
接下来N行的01串,表示N篇作文
Output
N行,每行一个整数,表示这篇作文的Lo 值。
Sample Input
1 2
10110
000001110
1011001100
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 }