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 }
View Code

相关文章: