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%

 

题解:

用所有的作文库字符串建一个广义后缀自动机。

对于每个询问,将其输入到后缀自动机中,求出每个前缀的最长匹配后缀。

根据后缀自动机的性质,成功多匹配一个字符时,匹配长度加1;跳到pre时,匹配长度变为step。

二分答案,利用单调队列求出当前限制下至少不能匹配多少个字符,检验是否可行。

 

代码(P++注意):

  1 #include<bits/stdc++.h>
  2 #define begin {
  3 #define end }
  4 #define while while(
  5 #define if if(
  6 #define do )
  7 #define then )
  8 #define for for(
  9 #define fillchar(a,b,c) memset(a,c,b)
 10 #define writeln printf("\n")
 11 #define write printf
 12 #define readln readl()
 13 #define inc(a) a++
 14 #define dec(a) a--
 15 #define exit(a) return a
 16 #define mod %
 17 #define div /
 18 #define shl <<
 19 #define shr >>
 20 #define extended long double
 21 #define longint int
 22 #define integer short
 23 #define int64 long long
 24 template<typename T> inline void read(T& a)
 25 begin
 26   T x=0,f=1; char ch=getchar();
 27   while(ch<'0')or(ch>'9')do
 28   begin
 29     if ch=='-' then f=-1; ch=getchar();
 30   end
 31   while(ch>='0')and(ch<='9')do
 32   begin
 33     x=x*10+ch-'0'; ch=getchar();
 34   end
 35   a=x*f;
 36 end
 37 inline void readl()
 38 begin
 39   char ch; ch=getchar();
 40   while ch!='\n' do ch=getchar();
 41 end
 42 using namespace std;
 43 int le,i,ii,j,k,l,r,ll,rr,mid,n,nn,m,ans,pre[3000005],step[3000005],a[3000005][2],last,now,q[3000005],f[3000005],lb[3000005];
 44 char s[3000005];
 45 bool dp(int x)
 46 begin
 47   l=1; if x<=1 then begin r=1; f[0]=0; lb[1]=0; end else r=0;
 48   for int i=1;i<=le;i++ do
 49   begin
 50     f[i]=f[i-1]+1;
 51     while(l<=r)and(lb[l]<q[i])do inc(l);
 52     if l<=r then f[i]=min(f[i],f[lb[l]]);
 53     if i-x+1>=0 then
 54     begin
 55       while(l<=r)and(f[lb[r]]>=f[i-x+1])do dec(r);
 56       inc(r); lb[r]=i-x+1;
 57     end
 58   end
 59   if f[le]*10<=le then exit(1);
 60   exit(0);
 61 end
 62 int main()
 63 begin
 64   read(n); read(nn); pre[0]=-1;
 65   for ii=1;ii<=nn;ii++ do 
 66   begin
 67     scanf("%s",s+1); le=strlen(s+1);  last=0;
 68     for i=1;i<=le;i++ do
 69     begin
 70       inc(m); now=m; step[now]=step[last]+1;
 71       while(last!=-1)and(a[last][s[i]-'0']==0)do
 72       begin a[last][s[i]-'0']=now; last=pre[last]; end
 73       if last==-1 then begin pre[now]=0; last=now; continue; end
 74       if step[last]+1==step[a[last][s[i]-'0']] then
 75       begin pre[now]=a[last][s[i]-'0']; last=now; continue; end
 76       j=a[last][s[i]-'0'];
 77       inc(m); a[m][0]=a[j][0]; a[m][1]=a[j][1]; pre[m]=pre[j]; step[m]=step[last]+1;
 78       pre[j]=m; pre[now]=m;
 79       while last!=-1 do
 80       begin
 81         if a[last][s[i]-'0']==j then a[last][s[i]-'0']=m;else break;
 82         last=pre[last];
 83       end
 84       last=now;
 85     end
 86     for i=1;i<=le;i++ do s[i]='\0';
 87   end
 88   for ii=1;ii<=n;ii++ do
 89   begin
 90     scanf("%s",s+1); le=strlen(s+1);
 91     now=0; last=0;
 92     for i=1;i<=le;i++ do
 93     begin
 94       while(now!=-1)and(a[now][s[i]-'0']==0)do begin now=pre[now]; if now!=-1 then last=step[now] ; end
 95       if now==-1 then begin now=0; last=0; end else begin now=a[now][s[i]-'0']; inc(last); end
 96       q[i]=i-last;
 97     end
 98     ans=0; ll=1; rr=le;
 99     while ll<=rr do
100     begin
101       mid=(ll+rr)div 2;
102       if dp(mid) then begin ans=mid; ll=mid+1; end
103       else rr=mid-1;
104     end
105     write("%d",ans); writeln;
106   end
107 end
View Code
posted @ 2017-03-03 11:16  GhoStreach  阅读(173)  评论(0编辑  收藏  举报