1. 程式人生 > >【字尾自動機】【單調佇列優化DP】BZOJ2806 Cheat

【字尾自動機】【單調佇列優化DP】BZOJ2806 Cheat

分析:

比較裸的字尾自動機題。

先求出每個字首能匹配的最大字尾。然後二分答案做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])
m a x l e n i maxlen_i 即以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);
	}
}