题目大意:
这题就是sam,再二分加上单调队列优化DP。。。
就是先用标准作文库先做一个sam,中间用2隔开就行了
然后对于每个串,就先放到sam里去匹配,找到最长可以匹配的长度v[i]
二分L,再dp, f[i]=max(f[k]-k)+i i-v[i]<=k<=i-L 因为i-v[i]与i-L都是单增的,所以可以用单调队列优化,最后判断是否f[n]是否大于等于n*0.9就行了
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const double eps=1e-8;
const int maxn=1100011;
int m,n;
void init(){scanf("%*d%d",&m);}
int v[maxn];
bool check(int limit){
static int q[maxn],head,tail,f[maxn];
q[head=1]=tail=0; f[0]=0;
for (int i=1,tmp;i<=n;++i){
f[i]=f[i-1];
if ((tmp=i-limit)>=0){
while (head<=tail && f[tmp]-tmp>=f[q[tail]]-q[tail]) --tail;
q[++tail]=tmp;
}
while (head<=tail && i-v[i]>q[head]) ++head;
if (head<=tail) f[i]=max(f[i],f[q[head]]+i-q[head]);
}
return f[n]>=n*0.9-eps;
}
struct Tsam{
struct Tnode{
Tnode *ch[3],*f; int ml;
void clear(){memset(ch,0,sizeof(0)); f=NULL; ml=0;}
}e[maxn<<1],*root,*last;
int tot;
Tnode *newnode(){e[tot].clear(); return e+(tot++);}
void clear(){tot=0; root=last=newnode();}
void add(int c){
Tnode *np=newnode(),*p=last; np->ml=p->ml+1;
for (last=np;p && !p->ch[c];p=p->f) p->ch[c]=np;
if (!p) return np->f=root,void();
Tnode *q=p->ch[c];
if (q->ml==p->ml+1) return np->f=q,void();
Tnode *r=newnode(); *r=*q; r->ml=p->ml+1;
for (q->f=np->f=r;p && p->ch[c]==q;p=p->f) p->ch[c]=r;
}
}sam;
char s[maxn];
void work(){
for (sam.clear();m;m--){
sam.add(2); scanf("%s",s);
for (int i=0;s[i];++i) sam.add(s[i]-'0');
}
while (scanf("%s",s+1)!=EOF){
n=strlen(s+1); Tsam::Tnode *p=sam.root;
for (int i=1,len=0,c;i<=n;++i){
c=s[i]-'0';
if (p->ch[c]) p=p->ch[c],++len;
else{
while (p && !p->ch[c]) p=p->f;
if (!p) p=sam.root,len=0;
else len=p->ml+1,p=p->ch[c];
}
v[i]=len;
}
int t=1,w=n,mid;
while (t<=w){
mid=(t+w)>>1;
if (check(mid)) t=mid+1;
else w=mid-1;
}
printf("%d\n",t-1);
}
}
int main(){
init();
work();
return 0;
}
切过一道CTSC的题就是爽啊,果然还是太弱了。。。