BZOJ2806:[CTSC2012]Cheat
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
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