Loading

LOJ-2123 最短不公共子串 后缀自动机,子序列自动机

LOJ-2123 最短不公共子串 后缀自动机,子序列自动机

前几天做了一道GYM的最短非公共子串,利用子序列自动机性质DP来做,后来又发现了此题 HEOI2015

题意

给定小写字母串\(A,B\) 计算

1.A的一个最短的子串,它不是B的子串

2.A的一个最短的子串,它不是B的子序列

3.A的一个最短的子序列,它不是B的子串

4.A的一个最短的子序列,它不是B的子序列

\[len \leq 2000 \]

分析

后缀自动机可以识别一个字符串的所有子串,子序列自动机可以识别一个字符串的所有子序列

于是我们发现只要建立两个串的后缀自动机和子序列自动机,在上面跑一遍BFS即可

复杂度\(O(n^2)\)

代码

struct Auto{
	int trans[maxn][26],maxlen[maxn],link[maxn],siz,last;
	int Last[maxn];
	int rt;
	void clear_sam(){
		rt = 1;
		memset(trans,0,sizeof trans);
		memset(link,0,sizeof link);
		last = siz = 1;
	}
	void clear_seq(){
		rt = 2015;
		memset(trans,0,sizeof trans);
		memset(Last,0,sizeof Last);
	}
	inline void extend(int id){
		int cur = ++siz,p;
		maxlen[cur] = maxlen[last] + 1;
		for(p = last;p && !trans[p][id];p = link[p]) trans[p][id] = cur;
		if(!p) link[cur] = 1;
		else{
			int q = trans[p][id];
			if(maxlen[q] == maxlen[p] + 1) link[cur] = q;
			else{
				int clone = ++siz;
				maxlen[clone] = maxlen[p] + 1;
				memcpy(trans[clone],trans[q],sizeof(trans[q]));
				link[clone] = link[q];
				for(;p && trans[p][id] == q;p = link[p]) trans[p][id] = clone;
				link[cur] = link[q] = clone;	
			}
		} 
		last = cur;
	}
	void sam(char *s){
		clear_sam();
		int len = strlen(s + 1);
		for(int i = 1;i <= len;i++) extend(s[i] - 'a');
	}
	void seq(char *s){
		clear_seq();
		int len = strlen(s + 1);
		for(int i = len;i >= 1;i--){
			for(int j = 0;j < 26;j++) trans[i][j] = Last[j];
			Last[s[i] - 'a'] = i;
		}
		for(int i = 0;i < 26;i++) trans[rt][i] = Last[i];
	}
}a,b;

struct node{
	int a,b,dep;
};

bool vis[maxn][maxn];
char s1[maxn],s2[maxn]; 

int query(){
	memset(vis,0,sizeof vis);
	queue<node> q;
	vis[a.rt][b.rt] = 1;
	q.push({a.rt,b.rt,0});
	while(!q.empty()) {
		node u = q.front();
		q.pop();
		for(int i = 0;i < 26;i++){
			int s = a.trans[u.a][i],t = b.trans[u.b][i];
			if(vis[s][t]) continue;
			if(s && !t) {
				return u.dep + 1;
			}
			vis[s][t] = 1;
			q.push({s,t,u.dep + 1});
		}
	}
	return -1;
}

int main(){
	scanf("%s%s",s1 + 1,s2 + 1);
	a.sam(s1);
	b.sam(s2);
	cout << query() << '\n';
	a.sam(s1);
	b.seq(s2);
	cout << query() << '\n';
	a.seq(s1);
	b.sam(s2);
	cout << query() << '\n';
	a.seq(s1);
	b.seq(s2);
	cout << query() << '\n';
}
posted @ 2021-04-12 18:41  MQFLLY  阅读(97)  评论(0编辑  收藏  举报