【后缀自动机】【单调队列优化DP】BZOJ2806 Cheat

  • Post author:
  • Post category:其他

分析:

比较裸的后缀自动机题。

先求出每个前缀能匹配的最大后缀。然后二分答案做DP

f

[

i

]

=

m

a

x

{

f

[

i

1

]

,

f

[

j

]

+

i

j

}

(

j

[

i

m

a

x

l

e

n

i

,

i

k

]

)

f[i]=max\{f[i-1],f[j]+i-j\}(j\in [i-maxlen_i,i-k])

f[i]=max{f[i1],f[j]+ij}(j[imaxleni,ik])

m

a

x

l

e

n

i

maxlen_i

maxleni即以i为结尾的前缀的最大匹配后缀长度。

很显然j的取值右端点是单增的,稍微证明一下也会发现左端点也是单增的。

然后就可以单调队列优化DP了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 1100010
#define MAXS 3
using namespace std;
struct node{
	int len;
	node *ch[MAXS];
	node *fail;	
}SuA[MAXN],*last,*ncnt,*rt;	
void Insert(int c){
	node *p=last;
	node *np=++ncnt;
	np->len=p->len+1;
	last=np;
	while(p&&!p->ch[c])
		p->ch[c]=np,p=p->fail;
	if(!p)
		np->fail=rt;
	else{
		node *q=p->ch[c];
		if(q->len==p->len+1)
			np->fail=q;
		else{
			node *nq=++ncnt;
			*nq=*q;
			nq->len=p->len+1;
			np->fail=q->fail=nq;
			while(p&&p->ch[c]==q)
				p->ch[c]=nq,p=p->fail;
		}
	}
}
int res[MAXN];
void match(char s[],int N){
	node *now=rt;
	int len=0;
	for(int i=0;i<N;i++){
		int c=s[i]-'0';
		if(now->ch[c]){
			len++;
			now=now->ch[c];	
		}
		else{
			while(now&&!now->ch[c])
				now=now->fail;
			if(!now)
				now=rt,len=0;
			else
				len=now->len+1,now=now->ch[c];
		}
		res[i]=len;
	}
}
int q[MAXN],tl,hd,f[MAXN];
int n,m;
bool check(int k,int len){
	hd=1;tl=0;
	for(int i=1;i<=len;i++){
		f[i]=f[i-1];
		if(i-k>=0){
			int add=i-k;
			while(hd<=tl&&f[q[tl]]-q[tl]<f[add]-add)
				tl--;
			q[++tl]=add;
		}
		while(hd<=tl&&q[hd]<i-res[i-1])
			hd++;
		if(hd<=tl)
			f[i]=max(f[i],f[q[hd]]-q[hd]+i);
	}
	return f[len]*10>=len*9;
}
void init(){
	rt=ncnt=last=SuA;	
}
char str[MAXN];
int main(){
	init();
	SF("%d%d",&n,&m);
	for(int i=0;i<m;i++){
		SF("%s",str);
		int len=strlen(str);
		for(int j=0;j<len;j++)
			Insert(str[j]-'0');
		Insert(2);	
	}
	for(int i=0;i<n;i++){
		SF("%s",str);
		int len=strlen(str);
		match(str,len);	
		int l=1,r=len,ans=0;
		while(l<=r){
			int mid=(l+r)>>1;
			if(check(mid,len)){
				ans=mid;
				l=mid+1;
			}
			else
				r=mid-1;
		}
		PF("%d\n",ans);
	}
}

版权声明:本文为qq_34454069原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。