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

Solution

强行四合一?

(一)枚举$A$串的左端点,然后从左端点开始往后在$B$串的$SAM$上面跑,一旦失配就更新答案然后$break$

(二)预处理数组$next[i][j]$表示从$i$后面的第一次出现字母$j$的位置。预处理出$nextA$和$nextB$,然后枚举$A$左端点往后贪心,如果失配就更新答案然后$break$

(三)设$len[i]$表示在$B$串的$SAM$的$i$点的时候最短的长度。然后用$A$串在$B$的$SAM$上面跑。如果失配就更新答案,否则就更新$len$。

(四)设$len[i]$表示在$B$串的$i$位置的时候最短的长度。然后用$A$串的每一个字母,借$next$数组倒序去更新$len$。如果失配就更新答案,否则就更新$len$。至于为什么要倒序,其实是和背包差不多的原理,并不难想。

Code

 #include<iostream>
#include<cstring>
#include<cstdio>
#define N (4009)
using namespace std; char s[N],t[N];
int slen,tlen,nextA[N][],nextB[N][],last[],len[N]; struct SAM
{
int son[N][],fa[N],step[N],wt[N],od[N];
int p,q,np,nq,last,cnt;
SAM(){last=cnt=;} void Insert(int x)
{
p=last; np=last=++cnt; step[np]=step[p]+;
while (p && !son[p][x]) son[p][x]=np, p=fa[p];
if (!p) fa[np]=;
else
{
q=son[p][x];
if (step[q]==step[p+]) fa[np]=q;
else
{
nq=++cnt; step[nq]=step[p]+;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq]=fa[q]; fa[np]=fa[q]=nq;
while (son[p][x]==q) son[p][x]=nq, p=fa[p];
}
}
}
}SAM; void CalcNext()
{
memset(last,-,sizeof(last));
for (int i=slen; i>=; --i)
{
for (int j=; j<; ++j) nextA[i][j]=last[j];
last[s[i]-'a']=i;
}
memset(last,-,sizeof(last));
for (int i=tlen; i>=; --i)
{
for (int j=; j<; ++j) nextB[i][j]=last[j];
last[t[i]-'a']=i;
}
} void Sub1()
{
int ans=2e9;
for (int i=; i<=slen; ++i)
{
int now=;
for (int j=i; j<=slen; ++j)
{
if (!SAM.son[now][s[j]-'a']) {ans=min(ans,j-i+); break;}
now=SAM.son[now][s[j]-'a'];
}
}
printf("%d\n",ans==2e9?-:ans);
} void Sub2()
{
int ans=2e9;
for (int i=; i<=slen; ++i)
{
int now=;
for (int j=i; j<=slen; ++j)
{
if (nextB[now][s[j]-'a']==-) {ans=min(ans,j-i+); break;}
now=nextB[now][s[j]-'a'];
}
}
printf("%d\n",ans==2e9?-:ans);
} void Sub3()
{
int ans=2e9;
memset(len,0x7f,sizeof(len));
len[]=;
for (int i=; i<=slen; ++i)
for (int j=; j<=SAM.cnt; ++j)
{
int nxt=SAM.son[j][s[i]-'a'];
if (!nxt) ans=min(ans,len[j]);
else len[nxt]=min(len[nxt],len[j]+);
}
printf("%d\n",ans==2e9?-:ans);
} void Sub4()
{
int ans=2e9;
memset(len,0x7f,sizeof(len));
len[]=;
for (int i=; i<=slen; ++i)
for (int j=tlen; j>=; --j)
{
int nxt=nextB[j][s[i]-'a'];
if (nxt==-) ans=min(ans,len[j]+);
else len[nxt]=min(len[nxt],len[j]+);
}
printf("%d\n",ans==2e9?-:ans);
} int main()
{
scanf("%s%s",s+,t+);
slen=strlen(s+), tlen=strlen(t+);
for (int i=; i<=tlen; ++i)
SAM.Insert(t[i]-'a');
CalcNext();
Sub1(); Sub2(); Sub3(); Sub4();
}

BZOJ4032:[HEOI2015]最短不公共子串(SAM)的更多相关文章

  1. bzoj4032: [HEOI2015]最短不公共子串(SAM+DP)

    4032: [HEOI2015]最短不公共子串 题目:传送门 题解: 陈年老题良心%你赛膜爆嘎爷 当初做题...一眼SAM...结果只会两种直接DP的情况... 情况1: 直接设f[i][j] 表示的 ...

  2. luoguP4112 [HEOI2015]最短不公共子串 SAM,序列自动机,广搜BFS

    luoguP4112 [HEOI2015]最短不公共子串 链接 luogu loj 思路 子串可以用后缀自动机,子序列可以用序列自动机. 序列自动机是啥,就是能访问到所有子序列的自动机. 每个点记录下 ...

  3. [BZOJ4032][HEOI2015]最短不公共子串(Trie+DP)

    在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之——被它们虐. 操作一:对A,B分别建SAM,暴力BFS. 操作二:对B建序列自动机或SAM,A在上面暴力匹配. 操作三:对A,B建 ...

  4. BZOJ4032: [HEOI2015]最短不公共子串(后缀自动机+序列自动机)

    题目描述 在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之. 一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是. 一个串的“子序列”指的是它的可以 ...

  5. BZOJ4032[HEOI2015]最短不公共子串——序列自动机+后缀自动机+DP+贪心

    题目描述 在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之. 一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是. 一个串的“子序列”指的是它的可以 ...

  6. BZOJ4032 [HEOI2015]最短不公共子串 【后缀自动机 + 序列自动机 + dp】

    题目链接 BZOJ4032 题解 首先膜\(hb\) 空手切神题 一问\(hash\),二问枚举 三问\(trie\)树,四问\(dp\) 南二巨佬神\(hb\) 空手吊打自动机 \(orz orz ...

  7. BZOJ4032 : [HEOI2015]最短不公共子串

    第一问: 对B串建立SAM,暴力枚举A的每个子串,在SAM上走,若失配则可行. 第二问: 设g[i][j]表示B串的第i个字符之后最早出现的字符j的位置,暴力枚举A的每个子串,按照g贪心地走,若失配则 ...

  8. 【BZOJ4032】[HEOI2015]最短不公共子串(后缀自动机,序列自动机)

    [BZOJ4032][HEOI2015]最短不公共子串(后缀自动机,序列自动机) 题面 BZOJ 洛谷 题解 数据范围很小,直接暴力构建后缀自动机和序列自动机,然后直接在两个自动机上进行\(bfs\) ...

  9. bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp)

    bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp) bzoj Luogu 题解时间 给两个小写字母串 $ A $ , $ B $ ,请你计算: ...

随机推荐

  1. <深入理解JavaScript>学习笔记(5)_强大的原型和原型链

    前言 JavaScript 不包含传统的类继承模型,而是使用 prototypal 原型模型. (prototypal :原型.学好英语还是很重要的) 虽然这经常被当作是 JavaScript 的缺点 ...

  2. Spring MVC No converter found for return value of type 解决方法

    1.在pom中添加 jackson <properties> <jackson.version>2.8.5</jackson.version> </prope ...

  3. oracle lpad rpad函数

    学习并记录 1.情况一 ) from dual; 运行结果如下: email长度5,默认添加3个空格在左边 2.情况二 ) from dual; 运行结果如下: email长度5,截取2两个字符 3. ...

  4. SSM框架文件远程服务器下载

    1.首先你必须要建立连接 获取URL的输入流 2.之后就是文件读取和写入了 3.还有就是设置响应头,响应码等 代码 @RequestMapping("/fileDownLoad") ...

  5. mybatis必知必会二

    关联: 嵌套查询:通过执行另外一个 SQL 映射语句来返回预期的复杂类型. 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集.首先,然让我们来查看这个元素的属性.所有的你都会看到,它和普通的只由 ...

  6. JSP简单实现登录和注销

    JSP简单实现登录和注销 需求:用户登录成功后跳转到欢迎页面 用户登录失败跳转到初始的登录界面 用户点击注销,用户退出登录状态需要重新登录 登录页面的JSP代码: <%@ page langua ...

  7. 【说文解字】Unix与Linux

    历史 Unix操作系统是由Ken Thompson和Dennis Ritchie于1969-1970年发明. 它的部分技术来源可以追溯到Multics工程,后者因为过于庞大复杂而失败. 研究人员吸取教 ...

  8. sql语句中as的意思是什么?

    as 一般用在两个地方,一个是query的时候,用来重新指定返回的column(列) 名字如:一个table 有个column叫 id, 我们的query是select id from table1. ...

  9. python学习之老男孩python全栈第九期_day023知识点总结——类和对象命名空间、组合

    一. 类和对象命名空间类里 可以定义两种属性: 1. 静态属性 2. 动态属性 class Course: language = 'Chinese' def __init__(self, teache ...

  10. 洛谷 P2469 [SDOI2010]星际竞速 解题报告

    题目描述 10年一度的银河系赛车大赛又要开始了.作为全银河最盛大的活动之一,夺得这个项目的冠军无疑是很多人的梦想,来自杰森座α星的悠悠也是其中之一. 赛车大赛的赛场由N颗行星和M条双向星际航路构成,其 ...