广义 \(SAM\) + 二分答案 + 单调队列优化 \(DP\)
对作文库建广义 \(SAM\) ,然后求出作文每个位置的最长匹配 \(d[i]\),然后二分答案 \(md\),然后 \(DP\) ,\(f[i]\) 表示到 \(i\) 的最大匹配长度,有 \(f[i]=\max(f[j]-j+i),j\in[i-d[i],i-md]\),最后检查 \(f[n]\geq 0.9\times len\)
#include<iostream>
#include<cstdio>
#include<cstring>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=2000010;
int n,m;
int d[N],f[N],q[N];
char s[N];
struct SAM {
int tot,lst,fa[N],c[N][2],len[N];
SAM() {tot=lst=1;}
inline void add(int ch) {
if(c[lst][ch]&&len[c[lst][ch]]==len[lst]+1)
return lst=c[lst][ch],void();
R p=lst,np=++tot,q,nq,flg=0;
len[np]=len[p]+1;
while(p&&!c[p][ch]) c[p][ch]=np,p=fa[p];
if(!p) fa[np]=1;
else {
q=c[p][ch];
if(len[q]==len[p]+1) fa[np]=q;
else {
if(p==lst) flg=1;
nq=++tot;
memcpy(c[nq],c[q],8);
fa[nq]=fa[q],len[nq]=len[p]+1;
fa[np]=fa[q]=nq;
while(p&&c[p][ch]==q) c[p][ch]=nq,p=fa[p];
}
} lst=flg?nq:np;
}
inline void calc() {
R n=strlen(s+1),p=1,l=0;
for(R i=1;i<=n;++i) {
R ch=s[i]-48;
while(p&&!c[p][ch]) p=fa[p],l=len[p];
if(p) p=c[p][ch],++l;
else p=1,l=0;
d[i]=l;
}
}
}s1;
inline bool ck(int md) {
R h=1,t=0,n=strlen(s+1);
memset(f,0,md<<2);
for(R i=md;i<=n;++i) {
f[i]=f[i-1];
while(h<=t&&f[q[t]]-q[t]<=f[i-md]-(i-md)) --t;
q[++t]=i-md;
while(h<=t&&q[h]<i-d[i]) ++h;
if(h<=t) f[i]=max(f[i],i+f[q[h]]-q[h]);
} return f[n]*10>=n*9;
}
inline void main() {
m=g(),n=g();
for(R i=1,len;i<=n;++i) { s1.lst=1;
scanf("%s",s+1),len=strlen(s+1);
for(R i=1;i<=len;++i) s1.add(s[i]-48);
}
for(R i=1;i<=m;++i) {
scanf("%s",s+1);
R l=0,r=strlen(s+1),md;
s1.calc();
while(l<r) {
md=(l+r+1)>>1;
if(ck(md)) l=md;
else r=md-1;
} printf("%d\n",l);
}
}
} signed main() {Luitaryi::main(); return 0;}
2020.01.10
原文地址:https://www.cnblogs.com/Jackpei/p/12177446.html
时间: 2024-10-04 23:58:58