P4112 [HEOI2015] 最短不公共子串
P4112 [HEOI2015] 最短不公共子串、
题目描述
在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。
下面给出一些定义:
- 一个串的“子串”指的是它的连续的一段,例如
bcd
是abcdef
的子串,但bde
不是。 - 一个串的“子序列”指的是它的可以不连续的一段,例如
bde
是abcdef
的子串,但bdd
不是。
下面,给两个小写字母串
的一个最短的子串,它不是 的子串。 的一个最短的子串,它不是 的子序列。 的一个最短的子序列,它不是 的子串。 的一个最短的子序列,它不是 的子序列。
数据规模与约定
- 对于
的数据,保证 和 的长度都不超过 。
Solution:
首先,我们不仅要构造后缀自动机,还要构造一个叫做序列自动机的东西,构造方法也十分简单,我们只需要记录每个字符最后一次出现的位置
然后在这两个自动机上面同步跑 bfs 就好了,至于四遍分别这么跑详见代码。
Code:
#include<bits/stdc++.h> const int N=4005; using namespace std; struct SAM{ int ch[N][26],fa[N],len[N]; int last,cnt; void init(){last=cnt=1;} void insert(int c) { int p=last,q=++cnt;last=q;len[q]=len[p]+1; for(;p&&!ch[p][c];p=fa[p])ch[p][c]=q; if(!p){fa[q]=1;return ;}int x=ch[p][c]; if(len[x]==len[p]+1){fa[q]=x;return ;} int y=++cnt;len[y]=len[p]+1;fa[y]=fa[x]; for(int i=0;i<26;i++)ch[y][i]=ch[x][i]; fa[x]=fa[q]=y; for(;p&&ch[p][c]==x;p=fa[p])ch[p][c]=y; } }SA,SB; struct SQM{ int ch[N][26],fa[N],last[26]; int cnt; void init(){cnt=1;for(int i=0;i<26;i++)last[i]=1;} void insert(int c) { int p=last[c],q=++cnt;fa[q]=p; for(int i=0;i<26;i++)for(int x=last[i];x&&!ch[x][c];x=fa[x]) ch[x][c]=q; last[c]=q; } }SQA,SQB; struct Node{ int x,y,len; }; int vis[N][N]; int bfs(int opt) { queue<Node> Q; Q.push({1,1,0}); vis[1][1]=opt; while(!Q.empty()) { int x=Q.front().x,y=Q.front().y,len=Q.front().len;Q.pop(); for(int i=0,xx,yy;i<26;i++) { xx=(opt<=2 ? SA.ch[x][i] : SQA.ch[x][i]),yy=(opt&1? SB.ch[y][i] : SQB.ch[y][i]); if(xx&&yy) { if(vis[xx][yy]==opt)continue; //if(opt==2)cout<<char(i+'a')<<" "<<x<<" "<<y<<":"<<xx<<" "<<yy<<" "<<len+1<<"\n"; vis[xx][yy]=opt; Q.push({xx,yy,len+1}); } if(xx&&!yy) return len+1; } } return -1; } int n,m; char A[N],B[N]; int ans[5]; void work() { scanf("%s%s",A+1,B+1); n=strlen(A+1);m=strlen(B+1); SA.init(),SB.init(),SQA.init(),SQB.init(); for(int i=1;i<=n;i++)SA.insert(A[i]-'a'),SQA.insert(A[i]-'a'); for(int i=1;i<=m;i++)SB.insert(B[i]-'a'),SQB.insert(B[i]-'a'); ans[1]=bfs(1);ans[2]=bfs(2);ans[3]=bfs(3),ans[4]=bfs(4); for(int i=1;i<=4;i++)printf("%d\n",ans[i]); } int main() { //freopen("sus.in","r",stdin);freopen("sus.out","w",stdout); work(); return 0; }