BZOJ 4032: [HEOI2015]最短不公共子串(后缀自动机+记忆化搜索)

传送门

解题思路

  首先需要预处理两个串\(nxt(i)(j)\)表示i位置之后最近的\(j\)
  第一问直接对\(b\)建后缀自动机,枚举\(a\)的起点暴力匹配。
  第二问枚举\(a\)的起点,\(b\)\(nxt\)跳。
  第三问\(a\)\(b\)一起跳,\(b\)用后缀自动机,\(a\)\(nxt\)
  第四问\(a\)\(b\)一起跳,都用\(nxt\),要加记忆化。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int N=2005;

inline int min(int x,int y) {return x<y?x:y;}

int lena,lenb,ans=1e9,nxta[N][27],prea[27],nxtb[N][27],preb[27];
int vis[N][N];
char A[N],B[N];

struct SAM{
	int lst,cnt,fa[N<<1],ch[N<<1][27],l[N<<1];
	inline void insert(int c){
		int p=lst,np=++cnt; lst=cnt; l[np]=l[p]+1;
		for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
		if(!p) fa[np]=1;
		else {
			int q=ch[p][c];
			if(l[q]==l[p]+1) fa[np]=q;
			else {
				int nq=++cnt; l[nq]=l[p]+1;
				memcpy(ch[nq],ch[q],sizeof(ch[q]));
				fa[nq]=fa[q]; fa[q]=fa[np]=nq;
				for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
			}
		}
	}
	inline int query1(int x){
		int p=1,ret=0;
		for(int i=x;i<=lena;i++) {
			if(ch[p][A[i]-'a']) p=ch[p][A[i]-'a'],ret++;
			else return ret+1;	
		}
		return 1e9;
	}
	inline void query3(int x,int y,int l){
		for(int i=0;i<26;i++){
			if(!ch[y][i] && nxta[x][i]) ans=min(ans,l);
			else if(ch[y][i] && nxta[x][i]) query3(nxta[x][i],ch[y][i],l+1);
		}
	}
}sam;

inline int query2(int x){
	int now=0,ret=0;
	for(int i=x;i<=lena;i++){
		if(!nxtb[now][A[i]-'a']) return ret+1;
		ret++; now=nxtb[now][A[i]-'a'];
	}
	return 1e9;
}

int query4(int x,int y){
	if(x && !y) return 1;
	if(vis[x][y]) return vis[x][y];
	int tmp=1e9;
	for(int i=0;i<26;i++){
		if(!nxta[x][i]) continue;
		tmp=min(tmp,query4(nxta[x][i],nxtb[y][i]));
	}
	vis[x][y]=tmp+1;
	return vis[x][y];
}

int main(){
	scanf("%s%s",A+1,B+1); sam.cnt=sam.lst=1;
	lena=strlen(A+1); lenb=strlen(B+1);
	for(int i=lena;~i;i--) {
		for(int j=0;j<26;j++) nxta[i][j]=prea[j];
		prea[A[i]-'a']=i; 
	}
	for(int i=lenb;~i;i--){
		for(int j=0;j<26;j++) nxtb[i][j]=preb[j];
		preb[B[i]-'a']=i;
	}	
	for(int i=1;i<=lenb;i++) sam.insert(B[i]-'a');
	for(int i=1;i<=lena;i++) ans=min(ans,sam.query1(i));
	printf("%d\n",(ans==1e9)?-1:ans); ans=1e9;
	for(int i=1;i<=lena;i++) ans=min(ans,query2(i));
	printf("%d\n",(ans==1e9)?-1:ans); ans=1e9; sam.query3(0,1,0);
	printf("%d\n",(ans==1e9)?-1:ans+1); ans=query4(0,0)-1;
	printf("%d\n",(ans==1e9)?-1:ans);
	return 0;
}
posted @ 2019-01-19 11:16  Monster_Qi  阅读(122)  评论(0编辑  收藏  举报