T1 bzoj 2806
题目大意:
给出$n$个字符串表示模式串,$m$次询问,每次给出一个串
对于一个模式串的子串,我们可以将其称为一个好的串
对于一个给出的串,需要将这个串划分为若干段,使得这些段中好的串的总长度不少于总长的$85%$
现在要使这个划分方案中最短的好的串的长度最大,输出这个满足条件的情况下最短串长度的最大值
思路:
很容易想到二分答案,得到$f_i=max(f_j+i-j),j<=i-mid$其中$s[j:i]$为一个加分句
用广义后缀自动机处理出每个点向前最远可以匹配到的位置
这个位置是单调上升的,用单调队列维护一个dp值单调下降的队列即可
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define db double 4 #define inf 2139062143 5 #define MAXN 2001000 6 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 7 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 8 #define ren for(register int i=fst[x];i;i=nxt[i]) 9 #define pls(a,b) (a+b)%MOD 10 #define mns(a,b) (a-b+MOD)%MOD 11 #define mul(a,b) (1LL*(a)*(b))%MOD 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+(ch&15);ch=getchar();} 18 return x*f; 19 } 20 int n,m,mxl[MAXN],pos[MAXN],fa[MAXN],tr[MAXN][2],las=1,tot=1; 21 int len,f[MAXN],q[MAXN],hd,tl; 22 char s[MAXN]; 23 void extend(int c) 24 { 25 int p=las,np=las=++tot;mxl[np]=mxl[p]+1; 26 for(;p&&!tr[p][c];p=fa[p]) tr[p][c]=np; 27 if(!p) {fa[np]=1;return ;}int q=tr[p][c]; 28 if(mxl[q]==mxl[p]+1) {fa[np]=q;return ;} 29 int nq=++tot;mxl[nq]=mxl[p]+1; 30 memcpy(tr[nq],tr[q],sizeof(tr[nq])); 31 fa[nq]=fa[q],fa[q]=fa[np]=nq; 32 for(;p&&tr[p][c]==q;p=fa[p]) tr[p][c]=nq; 33 } 34 int X(int x) {return f[x]-x;} 35 int cheq(int x) 36 { 37 hd=1,tl=0;rep(i,1,len) 38 { 39 f[i]=f[i-1];if(i<x) continue; 40 while(hd<=tl&&X(q[tl])<=X(i-x)) tl--;q[++tl]=i-x; 41 while(hd<=tl&&q[hd]<i-pos[i]) hd++; 42 if(hd<=tl) f[i]=max(f[i],f[q[hd]]+i-q[hd]); 43 } 44 return f[len]*20>=len*17; 45 } 46 int main() 47 { 48 n=read(),m=read();rep(i,1,m) 49 { 50 scanf("%s",s+1);len=strlen(s+1); 51 las=1;rep(i,1,len) extend(s[i]-'a'); 52 } 53 int p,c,res,l,r,mid,ans;rep(i,1,n) 54 { 55 scanf("%s",s+1);len=strlen(s+1),p=1,res=0; 56 rep(i,1,len) 57 { 58 c=s[i]-'a';if(tr[p][c]) {pos[i]=++res,p=tr[p][c];continue;} 59 for(;p&&!tr[p][c];p=fa[p]); 60 if(!p) pos[i]=res=0,p=1;else pos[i]=res=mxl[p]+1,p=tr[p][c]; 61 } 62 for(l=ans=0,r=len;mid=l+r>>1,l<=r;) 63 if(cheq(mid)) ans=mid,l=mid+1;else r=mid-1; 64 printf("%d\n",ans); 65 } 66 }