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';
}