【[HEOI2015]最短不公共子串】后缀自动机+序列自动机
1218 1218
4032: [HEOI2015]最短不公共子串
Time Limit: 10 Sec Memory Limit: 256 MB Submit: 815 Solved: 416 [Submit][Status][Discuss]Description
在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。
一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是。
一个串的“子序列”指的是它的可以不连续的一段,例如bde是abcdef的子串,但bdd不是。
下面,给两个小写字母串A,B,请你计算:
(1) A的一个最短的子串,它不是B的子串
(2) A的一个最短的子串,它不是B的子序列
(3) A的一个最短的子序列,它不是B的子串
(4) A的一个最短的子序列,它不是B的子序列
Input
有两行,每行一个小写字母组成的字符串,分别代表A和B。
Output
输出4行,每行一个整数,表示以上4个问题的答案的长度。如果没有符合要求的答案,输出-1.
Sample Input
aabbcc
abcabc
Sample Output
2
4
2
4
HINT
对于100%的数据,A和B的长度都不超过2000
我们考虑构建后缀自动机和序列自动机(类同后缀自动机,只是序列自动机是处理子序列问题,后缀自动机处理子串问题,会后缀自动机的话看代码就很好理解),然后放在两两自动机之间跑一个bfs就可以了。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn = 2005; char a[maxn],b[maxn]; struct hzzdh{ int son[maxn*2][26],par[maxn*2],mx[maxn*2],tot,las; void init() { las=tot=1; } void extend(int c) { int p=las,np=++tot;mx[np]=mx[p]+1; for(;p&&(!son[p][c]);p=par[p]) son[p][c]=np; las = np; if(!p) { par[np]=1; return; } int q = son[p][c]; if(mx[p]+1==mx[q]) { par[np]=q; return; } int nq = ++tot; memcpy(son[nq],son[q],sizeof son[q]); mx[nq] = mx[p]+1; par[nq]=par[q]; par[q] = par[np] = nq; for(;p&&son[p][c]==q;p=par[p]) son[p][c]=nq; } void insert(char *s) { int len = strlen(s+1); for(int i=1;i<=len;i++) extend(s[i]-'a'); } }sam[2]; struct xlzdj{ int son[maxn][26],la[26],par[maxn],tot; void init() { tot=1; for(int i=0;i<26;i++)la[i]=1;} void extend(int c) { int np = ++tot; par[np] = la[c]; for(int j=0;j<26;j++) for(int p=la[j];p&&(!son[p][c]);p=par[p]) son[p][c]=np; la[c]=np; } void insert(char *s) { int len = strlen(s+1); for(int i=1;i<=len;i++) extend(s[i]-'a'); } }sqm[2]; struct node{int o1,o2,d;}; queue<node>q; bool vis[maxn<<1][maxn<<1]; void solve(int a[][26],int b[][26]) { while(q.size())q.pop(); memset(vis,0,sizeof vis); vis[1][1]=1; q.push((node){1,1,0}); while(q.size()) { node u = q.front(); q.pop(); for(int c=0;c<26;c++) { node v = (node){a[u.o1][c],b[u.o2][c],u.d+1}; if(vis[v.o1][v.o2]||(!v.o1)) continue; if(!v.o2) { printf("%d\n",v.d); return; } q.push(v); vis[v.o1][v.o2]=1; } } puts("-1"); } int main() { scanf("%s%s",&a[1],&b[1]); sqm[0].init();sqm[1].init();sam[0].init();sam[1].init(); sqm[0].insert(a); sqm[1].insert(b); sam[0].insert(a); sam[1].insert(b); solve(sam[0].son,sam[1].son); solve(sam[0].son,sqm[1].son); solve(sqm[0].son,sam[1].son); solve(sqm[0].son,sqm[1].son); }