版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/82018404
Problem
Solution
注意到答案具有单调性,不妨考虑二分答案。设f[i]表示询问串前i位能匹配的最大长度,那么我们容易写出如下dp方程,其中pi表示的是当前串能匹配的最大长度:
那么可以先对主串建出广义后缀自动机,对于询问的串S,我们可以先跑出p数组,这样单次询问的复杂度是 。
把后面的那个式子丢进单调队列里维护就可以做到 的dp了。
时间复杂度
Code
#include <cstring>
#include <cstdio>
#define rg register
using namespace std;
const int maxn=2000010;
int n,m,lst,sz=1,len,ans,head;
int lth[maxn],f[maxn],pre[maxn],ch[maxn][2],l[maxn],q[maxn];
char s[maxn];
template <typename Tp> inline void getmax(Tp &x,Tp y){if(y>x) x=y;}
void insert(int c)
{
int p=lst,np=++sz;
lst=np;l[np]=l[p]+1;
for(;p&&!ch[p][c];p=pre[p]) ch[p][c]=np;
if(!p) pre[np]=1;
else
{
int q=ch[p][c];
if(l[q]==l[p]+1) pre[np]=q;
else
{
int nq=++sz;l[nq]=l[p]+1;
ch[nq][0]=ch[q][0];ch[nq][1]=ch[q][1];
pre[nq]=pre[q];pre[q]=pre[np]=nq;
for(;ch[p][c]==q;p=pre[p]) ch[p][c]=nq;
}
}
}
void match()
{
int x=1,now=0;
for(rg int i=1;i<=len;i++)
{
if(ch[x][s[i]-'0']) now++,x=ch[x][s[i]-'0'];
else
{
while(x&&!ch[x][s[i]-'0']) x=pre[x];
if(x) now=l[x]+1,x=ch[x][s[i]-'0'];
else x=1,now=0;
}
lth[i]=now;
}
}
int check(int k)
{
int head=0,tail=-1;
for(rg int i=0;i<k;i++) f[i]=0;
for(rg int i=k;i<=len;i++)
{
f[i]=f[i-1];
while(head<=tail&&f[i-k]-i+k>f[q[tail]]-q[tail]) tail--;
q[++tail]=i-k;
while(head<=tail&&q[head]<i-lth[i]) head++;
if(head<=tail) getmax(f[i],f[q[head]]-q[head]+i);
}
return f[len]*10>=len*9;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
scanf("%d%d",&n,&m);
while(m--)
{
scanf("%s",s+1);lst=1;
for(rg int i=1;s[i];i++) insert(s[i]-'0');
}
while(n--)
{
int L=1,R,mid;
scanf("%s",s+1);
R=len=strlen(s+1);
match();
while(L<=R)
{
mid=(L+R)>>1;
if(check(mid)) ans=mid,L=mid+1;
else R=mid-1;
}
printf("%d\n",ans);
}
return 0;
}