P4112 [HEOI2015] 最短不公共子串

P4112 [HEOI2015] 最短不公共子串

题目描述

在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。

下面给出一些定义:

  • 一个串的“子串”指的是它的连续的一段,例如 bcdabcdef 的子串,但 bde 不是。
  • 一个串的“子序列”指的是它的可以不连续的一段,例如 bdeabcdef 的子串,但 bdd 不是。

下面,给两个小写字母串 a,b,请你计算:

  1. a 的一个最短的子串,它不是 b 的子串。
  2. a 的一个最短的子串,它不是 b 的子序列。
  3. a 的一个最短的子序列,它不是 b 的子串。
  4. a 的一个最短的子序列,它不是 b 的子序列。

数据规模与约定

  • 对于 100% 的数据,保证 ab 的长度都不超过 2000

Solution:

首先,我们不仅要构造后缀自动机,还要构造一个叫做序列自动机的东西,构造方法也十分简单,我们只需要记录每个字符最后一次出现的位置 lastc 每次插入一个的时候枚举所有字符 p=lasti ,然后不断的跳 p=fap 直到其出现过 ch[p][c]

然后在这两个自动机上面同步跑 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;
}
posted @   liuboom  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示