题目大意:
有多个主串,每次询问将询问串分成多个连续子串,如果一个子串长度
≥
L
≥L
≥L且在主串中出现过就是合法的
如果合法的子串总长度
≥
≥
≥询问串长的
90
%
90\%
90%,这个串就是合法的字符串,求使得询问串成为合法的字符串的最大的
L
L
L。
分析:
我们可以二分答案,显然答案越大可以使用的合法串就越多,而且是包含关系,满足二分性。
我们把这些串建一个广义后缀自动机。
设
f
[
i
]
f[i]
f[i]前
i
i
i个位置最多可以覆盖多少个位置。
显然有
f
[
i
]
=
m
a
x
(
f
[
i
−
1
]
,
f
[
j
]
+
i
−
j
)
j
∈
[
i
−
m
a
x
c
,
i
−
m
i
d
l
e
n
]
f[i]=max(f[i-1],f[j]+i-j) j\in[i-maxc,i-midlen]
f[i]=max(f[i−1],f[j]+i−j)j∈[i−maxc,i−midlen]
其中
m
a
x
c
maxc
maxc是以当前位置结尾的询问串后缀在所有主串中的
l
c
s
lcs
lcs。
这个可以在后缀自动机上跳
f
a
i
l
fail
fail。
分三种情况讨论,如果当前节点有儿子,直接往儿子走,maxlen+1。
如果当前点没有这个儿子,跳fail到有这个儿子的节点,显然这个节点代表的串都是可以的(因为后缀自动机每个节点代表不止一个串,但是都是后缀关系),那么显然取最长那个,即
m
a
x
l
e
n
=
t
[
x
]
.
l
e
n
+
1
maxlen=t[x].len+1
maxlen=t[x].len+1。
如果没有找到儿子,直接
m
a
x
l
e
n
=
0
maxlen=0
maxlen=0。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
const int maxn=3e6+7;
using namespace std;
int n,m,cnt,len,head,tail;
int f[maxn],q[maxn];
char s[maxn];
struct node{
int len,fail;
int son[2];
}t[maxn];
struct rec{
int son[2];
}a[maxn];
void ins()
{
int now=1;
len=strlen(s+1);
for (int i=1;i<=len;i++)
{
int c=s[i]-'0';
if (!a[now].son[c]) a[now].son[c]=++cnt;
now=a[now].son[c];
}
}
int ins_sam(int x,int c)
{
int now,p,q,clone;
p=x;
if (t[p].son[c])
{
q=t[p].son[c];
if (t[p].len+1==t[q].len) return q;
clone=++cnt;
t[clone]=t[q];
t[clone].len=t[p].len+1;
t[q].fail=clone;
while (p&&(t[p].son[c]==q)) t[p].son[c]=clone,p=t[p].fail;
return clone;
}
now=++cnt;
t[now].len=t[p].len+1;
while (p&&(!t[p].son[c])) t[p].son[c]=now,p=t[p].fail;
if (!p) t[now].fail=1;
else
{
q=t[p].son[c];
if (t[p].len+1==t[q].len) t[now].fail=q;
else
{
clone=++cnt;
t[clone]=t[q];
t[clone].len=t[p].len+1;
t[now].fail=t[q].fail=clone;
while (p&&(t[p].son[c]==q)) t[p].son[c]=clone,p=t[p].fail;
}
}
return now;
}
void dfs(int x,int last)
{
int d;
if (a[x].son[0])
{
d=ins_sam(last,0);
dfs(a[x].son[0],d);
}
if (a[x].son[1])
{
d=ins_sam(last,1);
dfs(a[x].son[1],d);
}
}
bool check(int k)
{
int p=1,maxlen=0;
f[0]=0;
head=1,tail=0;
for (int i=1;i<=len;i++)
{
int c=s[i]-'0';
if (t[p].son[c]) maxlen++,p=t[p].son[c];
else
{
while (p&&(!t[p].son[c])) p=t[p].fail;
if (!p) p=1,maxlen=0;
else
{
maxlen=t[p].len+1;
p=t[p].son[c];
}
}
f[i]=f[i-1];
if (i-k>=0) q[++tail]=i-k;
while ((head<tail) && (f[q[tail]]-q[tail]>=f[q[tail-1]]-q[tail-1])) q[tail-1]=q[tail],tail--;
if (maxlen>=k)
{
while (q[head]<i-maxlen) head++;
if (q[head]<=i-k) f[i]=max(f[i],f[q[head]]+(i-q[head]));
}
}
return f[len]*10>=len*9;
}
int main()
{
scanf("%d%d",&m,&n);
cnt=1;
for (int i=1;i<=n;i++)
{
scanf("%s",s+1);
ins();
}
cnt=1;
dfs(1,1);
for (int i=1;i<=m;i++)
{
scanf("%s",s+1);
len=strlen(s+1);
int l=1,r=len,ans=0;
while (l<=r)
{
int mid=(l+r)/2;
if (check(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
printf("%d\n",ans);
}
}