您的位置:首页 > 其它

[BZOJ4032] [HEOI2015] 最短不公共子串 - 后缀自动机,序列自动机,BFS

2016-09-18 13:53 465 查看

4032: [HEOI2015]最短不公共子串

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 398  Solved: 189

[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

Source



[Submit][Status][Discuss]

HOME Back

其实序列自动机就是一个纸张的能遍历出所有子序列的自动机。。其实就是每个点的右边的不同字符的最近出现位置。

那么我们这些询问怎么做呢,首先我们建出每个串的后缀自动机和序列自动机,这样我们就能遍历所有的子序列了。

然后这样第一个询问随便用两个后缀自动机来BFS一下就好了(最简单的询问,trie或者hash都可以)。

那么第二个询问怎么搞呢,这个时候我们就发现一个显然对于4个询问都承认的限制:若用dp[i][j]表示第一个串在自动机上匹配到i位置,第二个串在自动机上匹配到j位置,那么显然dp[i][j]最小。

所以我们只要BFS就可以满足这样的要求。我们对于第二个询问匹配第一个串的后缀自动机(遍历所有子串)和序列自动机(遍历所有子序列),同理我们匹配不同的自动机,可以解决这个问题。

时间复杂度O(n^2*26)

#include"bits/stdc++.h"
#define F(i,l,r) for(int i=l;i<=r;i++)
#define D(i,r,l) for(int i=r;i>=l;i--)
using namespace std;
const int N=2005,M=26;
char s1
,s2
;
struct SequenceAutoMaton{
int a
,e
[M],n,last[M];
void pre(char*s){
n=strlen(s+1);
D(i,n,1){
memcpy(e[i+1],last,sizeof(int[M]));
a[i]=s[i]-'a';last[a[i]]=i+1;
}
memcpy(e[1],last,sizeof(int[M]));
}
} sqa[2];
struct SuffixAutoMaton{
int a[N*2],e[N*2][M],fail[N*2],d[N*2],last,n,nd;
SuffixAutoMaton(){nd=last=1;}
void extend(int c){
int np=++nd,p=last;d[np]=d[last]+1;
for(;!e[p][c]&&p;e[p][c]=np,p=fail[p]);
if(!p)fail[np]=1;
else {
int q=e[p][c],nq;
if(d[q]==d[p]+1)fail[np]=q;
else {
nq=++nd;d[nq]=d[p]+1;
memcpy(e[nq],e[q],sizeof(int[M]));
fail[nq]=fail[q];fail[np]=fail[q]=nq;
for(;e[p][c]==q;e[p][c]=nq,p=fail[p]);
}
}
last=np;
}
void pre(char*s){
n=strlen(s+1);
F(i,1,n){
a[i]=s[i]-'a';
extend(a[i]);
}
}
} sam[2];
int dp[2*N][2*N],q1[N*N],q2[N*N],l,r;
template<class T1,class T2>
void DP(T1&x,T2&y){
q1[1]=q2[1]=1;
memset(dp,0,sizeof(dp));
for(l=r=1;l<=r;l++){
F(i,0,25){
int dx=x.e[q1[l]][i],dy=y.e[q2[l]][i];
if(!dx)continue;
if(!dy){
printf("%d\n",dp[q1[l]][q2[l]]+1);
return;
}
if(dp[dx][dy])continue;
dp[dx][dy]=dp[q1[l]][q2[l]]+1;
++r;q1[r]=dx;q2[r]=dy;
}
}
puts("-1");
}
int main(){
scanf("%s\n%s",s1+1,s2+1);
sqa[0].pre(s1),sqa[1].pre(s2);
sam[0].pre(s1),sam[1].pre(s2);
DP(sam[0],sam[1]);DP(sam[0],sqa[1]);
DP(sqa[0],sam[1]);DP(sqa[0],sqa[1]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: