BZOJ4032:[HEOI2015]最短不公共子串(SAM)
Description
在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。
Input
有两行,每行一个小写字母组成的字符串,分别代表A和B。
Output
输出4行,每行一个整数,表示以上4个问题的答案的长度。如果没有符合要求的答案,输出-1.
Sample Input
abcabc
Sample Output
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)的更多相关文章
- bzoj4032: [HEOI2015]最短不公共子串(SAM+DP)
4032: [HEOI2015]最短不公共子串 题目:传送门 题解: 陈年老题良心%你赛膜爆嘎爷 当初做题...一眼SAM...结果只会两种直接DP的情况... 情况1: 直接设f[i][j] 表示的 ...
- luoguP4112 [HEOI2015]最短不公共子串 SAM,序列自动机,广搜BFS
luoguP4112 [HEOI2015]最短不公共子串 链接 luogu loj 思路 子串可以用后缀自动机,子序列可以用序列自动机. 序列自动机是啥,就是能访问到所有子序列的自动机. 每个点记录下 ...
- [BZOJ4032][HEOI2015]最短不公共子串(Trie+DP)
在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之——被它们虐. 操作一:对A,B分别建SAM,暴力BFS. 操作二:对B建序列自动机或SAM,A在上面暴力匹配. 操作三:对A,B建 ...
- BZOJ4032: [HEOI2015]最短不公共子串(后缀自动机+序列自动机)
题目描述 在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之. 一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是. 一个串的“子序列”指的是它的可以 ...
- BZOJ4032[HEOI2015]最短不公共子串——序列自动机+后缀自动机+DP+贪心
题目描述 在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之. 一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是. 一个串的“子序列”指的是它的可以 ...
- BZOJ4032 [HEOI2015]最短不公共子串 【后缀自动机 + 序列自动机 + dp】
题目链接 BZOJ4032 题解 首先膜\(hb\) 空手切神题 一问\(hash\),二问枚举 三问\(trie\)树,四问\(dp\) 南二巨佬神\(hb\) 空手吊打自动机 \(orz orz ...
- BZOJ4032 : [HEOI2015]最短不公共子串
第一问: 对B串建立SAM,暴力枚举A的每个子串,在SAM上走,若失配则可行. 第二问: 设g[i][j]表示B串的第i个字符之后最早出现的字符j的位置,暴力枚举A的每个子串,按照g贪心地走,若失配则 ...
- 【BZOJ4032】[HEOI2015]最短不公共子串(后缀自动机,序列自动机)
[BZOJ4032][HEOI2015]最短不公共子串(后缀自动机,序列自动机) 题面 BZOJ 洛谷 题解 数据范围很小,直接暴力构建后缀自动机和序列自动机,然后直接在两个自动机上进行\(bfs\) ...
- bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp)
bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp) bzoj Luogu 题解时间 给两个小写字母串 $ A $ , $ B $ ,请你计算: ...
随机推荐
- 验证是否是正整数,是否是mail,是否是正确的身份证
/// <summary> /// 通用验证类 /// </summary> class DataValidate { /// <summary> /// 验证正整 ...
- 总结:Python学习 和 Python与C/C++交互
本篇仅仅是Python的学习和Python和C++数据对接过程中的一些总结. 由于工作的需要,用一周的时间学习 Python. Python是基于C实现的一门解释型语言,由于其易用性,俘获了不少开发者 ...
- netty源代码编译_mac os
工作中会用到netty,有随手整理笔记的习惯,故学习整理下,之前看过了理论知识,接下来就看下源码了,先来编译下 个人 fork git:https://github.com/ending06/nett ...
- Socket的基本操作
socket的基本操作: (1)socket()函数: (2)bind()函数: (3)listen(),connect()函数: (4)accept()函数: (5)socket中的发送与接收函数: ...
- SqlServer示例数据库Northwind(一)——实体关系
在学习Spss统计分析.EA画实体关系图.PowerDesigner画数据库模型图等时,苦于找不到一个好的实例.由于实际工作中项目使用的表结构属于公司的商业保密内容,且在和大家交流时,其结构大家也不熟 ...
- Tinymce 编辑器添加自定义图片管理插件
在使用Tinymce的过程中需要用到图片上传功能,而提供的上传插件在上传文件后是给了一个连接地址,就想用户需要什么图片,不能用最直观的方式表现出来么! 虽然官网上也有一个文件管理的插件moxieman ...
- BZOJ3512:DZY Loves Math IV
传送门 Sol 好神仙的题目.. 一开始就直接莫比乌斯反演然后就 \(GG\) 了 orz 题解 permui 枚举 \(n\),就是求 \(\sum_{i=1}^{n}S(i,m)\) 其中\(S( ...
- Laravel基本使用
laravel一.简介二.运行环境要求 1.php 版本>=5.5.9 2.Mcrypt PHP扩展 php的加密扩展,提供多种加密算法 3.openssl扩展 对传输的数据进行加密 4.mbs ...
- BootstrapValidator超详细教程
一.引入必要文件 下载地址:(https://github.com/nghuuphuoc/bootstrapvalidator/archive/v0.4.5.zip) <link rel=&qu ...
- 相比之前其他几个入门的, 推荐: 简单vue2 入门教程
注意:Vue.js 不支持 IE8 及其以下 IE 版本. 具体可以看下 http://www.runoob.com/vue2/vue-tutorial.html 以下是学习过程 Vue ...