题目描述
阿米巴是小强的好朋友。
在小强眼中,阿米巴是一个作文成绩很高的文艺青年。为了获取考试作文的真谛,小强向阿米巴求教。阿米巴给小强展示了几篇作文,小强觉得这些文章怎么看怎么觉得熟悉,仿佛是
某些范文拼拼凑凑而成的。小强不禁向阿米巴投去了疑惑的眼光,却发现阿米巴露出了一个狡黠的微笑。为了有说服力地向阿米巴展示阿米巴的作文是多么让人觉得“眼熟”,小强想出了一个评定作文 “熟悉程度”的量化指标:\(L_0\) .小强首先将作文转化成一个 \(01\) 串。之后,小强搜集了各路名家的文章,同样分别转化成 \(01\) 串后,整理出一个包含了 \(M\) 个 \(01\) 串的“ 标准作文库 ”。
小强认为:如果一个 \(01\) 串长度不少于 \(L\) 且在标准作文库中的某个串里出现过(即,它是标准作文库的某个串的一个连续子串),那么它是“ 熟悉 ”的。对于一篇作文(一个 \(01\) 串)\(A\),如果能够把 \(A\) 分割成若干段子串,其中“ 熟悉 ” 的子串的 长度总和不少于 \(A\) 总长度的 \(90\%\),那么称 \(A\) 是 “ 熟悉的文章 ”。 \(L_0\) 是 能够让 $A $成为 “ 熟悉的文章 ” 的 所有 \(L\) 的最大值 (如果不存在这样的 \(L\),那么规定 \(L_0=0\))
被\(SAM\)和\(dp\)爆切就很难受
首先我们发现这个\(L\)显然有单调性,考虑二分
设 \(dp_i\) 表示匹配到第 \(i\) 位的最大匹配长度,然后处理 \(len_i\) 表示第 \(i\) 位能匹配到的最长子串
然后可以设计状态转移方程
首先很显然的 \(dp_i=dp_{i-1}\)
然后考虑其他转移 \(dp_i=\min\limits_{i-len_i \le j\le i-mid}dp_j+i-j\)
这个 \(dp\) 是 \(O(n^2)\) 的,考虑优化
发现可选区间右端点单调,且每个 \(dp\) 之间的优劣不会改变,可以用单调队列优化
复杂度\(O(\sum|T|log|T|)\)
AC代码
#include
#define ll long long
#define cri const register int
#define re register
#define len(tt) t[tt].len
#define c(xx,yy) t[xx].ch[yy]
#define f(xx) t[xx].f
using namespace std;
struct node{
int ch[3],f,len;
}t[2200010];
int tot=1,rt,las,L[1200010],dp[1200010];
inline void add(cri x){
int p=las,np=las=++tot;
len(np)=len(p)+1;
for(;p&&!c(p,x);p=f(p)) c(p,x)=np;
if(!p) f(np)=rt;
else{
int q=c(p,x);
if(len(q)==len(p)+1) f(np)=q;
else {
int nq=++tot;t[nq]=t[q];
len(nq)=len(p)+1;
f(np)=f(q)=nq;
for(;p&&c(p,x)==q;p=f(p)) c(p,x)=nq;
}
}
}
int LEN,que[1100010],n;
char s[1100010];
inline void match(){
int len=0,now=rt;
for(int i=1;i<=LEN;i++){
int in=s[i]-'0';
if(c(now,in)) now=c(now,in),len++;
else{
for(;now&&!c(now,in);now=f(now));
if(!now) now=rt,len=0;
else len=len(now)+1,now=c(now,in);
}
L[i]=len;
}
}
inline bool check(cri mid){
int now=rt,l=1,r=0;
for(int i=1;i=0.9L*LEN;
}
int main(){
int N,M;
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++){
rt=las=1;
scanf("%s",s+1);LEN=strlen(s+1);
for(int j=1;j<=LEN;j++) add(s[j]-'0');
add(2);
}
for(int i=1;i<=N;i++){
scanf("%s",s+1);LEN=strlen(s+1);
match();
int l=0,r=LEN;
while(l>1;
if(check(mid)) l=mid;
else r=mid-1;
}
printf("%d\n",l);
}
}
){> ;i++)>