题目链接

BZOJ4032

题解

首先膜\(hb\)

空手切神题

一问\(hash\),二问枚举

三问\(trie\)树,四问\(dp\)

南二巨佬神\(hb\)

空手吊打自动机

\(orz orz orz orz orz orz orz\)

咳。说正解

要处理子串,直接搬上后缀自动机

要处理子序列,直接搬上序列自动机【雾】

何为序列自动机##

序列自动机其实很简单,就是具有识别所有子序列功能的自动机

建机原理及过程及其简单,只需要从后往前扫一遍,对每一个位置建立一个节点,该节点的各个边连向最晚出现的对应的字符对应的节点

只需记录下每个字符最晚出现的节点就可以\(O(n|s|)\)建机了 【\(|s|\)为字符集大小】

代码实现:

struct LAM{
int ch[maxn][26],last[26],cnt;
void ins(int x){
int p = ++cnt;
for (int i = 0; i < 26; i++)
ch[p][i] = last[i];
last[x] = p;
}
void init(){
for (int i = 0; i < 26; i++)
ch[1][i] = last[i];
}
}lam;
......
lam.cnt = 1;
for (int i = len; i; i--) lam.ins(s[i] - 'a');
lam.init();

第一、二问##

只需枚举\(A\)子串的起点,然后看看能在自动机中走多远即可

第三、四问##

与\(A\)的子序列有关,就上\(dp\)

设\(f[i][j]\)表示\(A\)的前\(i\)个字符形成的所有子序列匹配到自动机\(j\)号节点的最短长度

如果\(i\)不选

\[f[i][j] = f[i - 1][j]
\]

如果\(i\)被选,那么枚举是从哪一个节点转移来的

设上一个节点为\(u\)

\[f[i][j] = min\{f[i - 1][u] + 1\}
\]

【注意这里是枚举\(u\)】

答案即为\(f[len][0]\) 【\(0\)表示空,即不匹配】

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 4005,maxm = 100005,INF = 0x3f3f3f3f;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
struct SAM{
int ch[maxn][26],pre[maxn],step[maxn],last,cnt;
void ins(int x){
int p = last,np = ++cnt; step[np] = step[p] + 1; last = np;
while (p && !ch[p][x]) ch[p][x] = np,p = pre[p];
if (!p) pre[np] = 1;
else {
int q = ch[p][x];
if (step[q] == step[p] + 1) pre[np] = q;
else {
int nq = ++cnt; step[nq] = step[p] + 1;
for (int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
pre[nq] = pre[q]; pre[np] = pre[q] = nq;
while (ch[p][x] == q) ch[p][x] = nq,p = pre[p];
}
}
}
}sam;
struct LAM{
int ch[maxn][26],last[26],cnt;
void ins(int x){
int p = ++cnt;
for (int i = 0; i < 26; i++)
ch[p][i] = last[i];
last[x] = p;
}
void init(){
for (int i = 0; i < 26; i++)
ch[1][i] = last[i];
}
}lam;
char A[maxn],B[maxn];
int lena,lenb;
void solve1(){
int ans = INF;
for (int i = 1,j; i <= lena; i++){
int u = 1,cnt = 0;
for (j = i; j <= lena; j++){
++cnt;
if (!sam.ch[u][A[j] - 'a']) break;
u = sam.ch[u][A[j] - 'a'];
}
if (j <= lena) ans = min(ans,cnt);
}
if (ans == INF) puts("-1");
else printf("%d\n",ans);
}
void solve2(){
int ans = INF;
for (int i = 1,j; i <= lena; i++){
int u = 1,cnt = 0;
for (j = i; j <= lena; j++){
++cnt;
if (!lam.ch[u][A[j] - 'a']) break;
u = lam.ch[u][A[j] - 'a'];
}
if (j <= lena) ans = min(ans,cnt);
}
if (ans == INF) puts("-1");
else printf("%d\n",ans);
}
int f[2005][maxn];
void solve3(){
memset(f,INF,sizeof(f));
f[0][1] = 0;
for (int i = 1; i <= lena; i++){
for (int j = 1; j <= sam.cnt; j++) f[i][j] = min(f[i][j],f[i - 1][j]);
for (int j = 1; j <= sam.cnt; j++){
int to = sam.ch[j][A[i] - 'a'];
f[i][to] = min(f[i][to],min(f[i - 1][to],f[i - 1][j] + 1));
}
}
if (f[lena][0] == INF) puts("-1");
else printf("%d\n",f[lena][0]);
}
void solve4(){
memset(f,INF,sizeof(f));
f[0][1] = 0;
for (int i = 1; i <= lena; i++){
for (int j = 1; j <= lam.cnt; j++) f[i][j] = min(f[i][j],f[i - 1][j]);
for (int j = 1; j <= lam.cnt; j++){
int to = lam.ch[j][A[i] - 'a'];
f[i][to] = min(f[i][to],min(f[i - 1][to],f[i - 1][j] + 1));
}
}
if (f[lena][0] == INF) puts("-1");
else printf("%d\n",f[lena][0]);
}
int main(){
scanf("%s",A + 1); lena = strlen(A + 1);
scanf("%s",B + 1); lenb = strlen(B + 1);
sam.last = sam.cnt = 1; lam.cnt = 1;
for (int i = 1; i <= lenb; i++) sam.ins(B[i] - 'a');
for (int i = lenb; i; i--) lam.ins(B[i] - 'a');
lam.init();
solve1();
solve2();
solve3();
solve4();
return 0;
}

BZOJ4032 [HEOI2015]最短不公共子串 【后缀自动机 + 序列自动机 + dp】的更多相关文章

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

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

  2. BZOJ 4032: [HEOI2015]最短不公共子串 后缀自动机 暴力

    4032: [HEOI2015]最短不公共子串 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4032 Description 在虐各种最 ...

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

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

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

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

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

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

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

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

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

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

  8. bzoj 4032 [HEOI2015]最短不公共子串——后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4032 不是 b 的子串的话就对 b 建后缀自动机,在 a 上枚举从每个位置开始的子串或者找子 ...

  9. BZOJ 4032: [HEOI2015]最短不公共子串(后缀自动机+记忆化搜索)

    传送门 解题思路 首先需要预处理两个串\(nxt(i)(j)\)表示i位置之后最近的\(j\). 第一问直接对\(b\)建后缀自动机,枚举\(a\)的起点暴力匹配. 第二问枚举\(a\)的起点,\(b ...

随机推荐

  1. django连接mysql数据库配置,出现no module named mysqldb报错

    作为一个菜鸟运维也是要有梦想的,万一学会了python走向人生巅峰了呢.好吧,都是瞎想,今天主要介绍下django配置,最近也开始摸索这个牛b框架了,当然大佬肯定不屑一顾,都是照顾照顾我们这些菜鸟初学 ...

  2. LINUX安装好后无法访问网络

    LINUX安装好后无法访问网络 在虚拟机安装好新的LINUX系统后,ping www.baidu.com ,发现无法ping通. 键入ifconfig查询配置: eno16777728: flags= ...

  3. js | JavaScript中数据类型转换总结

    转载 在js中,数据类型转换分为显式数据类型转换和隐式数据类型转换. 1, 显式数据类型转换 a:转数字: 1)Number转换: 代码: var a = “123”; a = Number(a); ...

  4. IDEA的使用方法(一)(IDEA基本快捷键)

    一个软件的快捷键显得尤为重要,接下来来讲讲快捷键 CTR+N 搜索类 CTR+SHIT+N 搜索文件 CTR+ALT+空格 代码提示(类似于 ALT+/) ALT+F7 查询在某处使用 CTR+Q 查 ...

  5. 7-1 python 操作redis

    1.安装并导入redis模块 # pip install redis 安装redis模块 import redis # 导入redis模块 2.连接一个或多个redis,指定数据库名,并指定返回字符串 ...

  6. Nginx 配置继承模型

    要了解nginx的继承模型,首先需要知道nginx使用多个配置块进行操作.在nginx中,这样的块被称为上下文,例如,放置在服务器上下文中的配置指令驻留在server { }块中,就像放置在http上 ...

  7. php扩展开发-INI配置

    php.ini文件是用来保存各项扩展配置的文件,每个扩展都或多或少需要有一个定制化的配置,ini文件是一个很好的保存配置的方式,我们来看下怎么在自己的扩展里,使用到ini的配置功能 //创建ini的配 ...

  8. vue 改变我们插值的符号{{}}改为${}

    delimiters的作用是改变我们插值的符号.Vue默认的插值是双大括号{{}}.但有时我们会有需求更改这个插值的形式. delimiters:['${','}'] 现在我们的插值形式就变成了${} ...

  9. python3爬取咪咕音乐榜信息(附源代码)

    参照上一篇爬虫小猪短租的思路https://www.cnblogs.com/aby321/p/9946831.html,继续熟悉基础爬虫方法,本次爬取的是咪咕音乐的排名 咪咕音乐榜首页http://m ...

  10. iOS常用控件-UITableViewCell

    一. 封装cell: 1.加载xib文件的两种方式 <方式1> (NewsCell是xib文件的名称) NSArray *objects = [[NSBundle mainBundle] ...