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

bzoj Luogu

题解时间

给两个小写字母串 $ A $ , $ B $ ,请你计算:

(1) $ A $ 的一个最短的子串,它不是 $ B $ 的子串

(2) $ A $ 的一个最短的子串,它不是 $ B $ 的子序列

(3) $ A $ 的一个最短的子序列,它不是 $ B $ 的子串

(4) $ A $ 的一个最短的子序列,它不是 $ B $ 的子序列

水题四合一,一题更比四题sao

首先由于都是要从 $ A $ 中找,所以按照套路是把 $ A $ 在 $ B $ 上匹配

所以先构建出 $ B $ 的SAM和序列自动机。

序列自动机:就是一个 $ next[i][ch] $ 数组表示第 $ i $ 位往后第一个出现字符 $ ch $ 的位置,纯粹用来匹配的。

(1) 直接以 $ A $ 每一位为起点在 $ B $ 的SAM上暴力匹配,只要失配就更新答案然后跳出。

(2) 换成在序列自动机上。

(3) $ dp[i][j] $ 表示 $ A $ 的前 $ i $ 个字符形成的子序列在 $ B $ 的SAM上匹配到了 $ j $ 位置,此时形成的最短子序列长度,这是个挺经典的dp了。

(4) 换成在序列自动机上。

#include<bits/stdc++.h>
using namespace std;
namespace RKK
{
const int N=2011,inf=0x3f3f3f3f;
int n1;char s1[N];
int n2;char s2[N];
struct remilia{int tranc[26],len,pre;};
struct sakuya
{
remilia s[N<<1];
int fin,size;
sakuya(){fin=size=1;}
void ins(int ch)
{
int npx,npy,lpx,lpy;
npx=++size;
s[npx].len=s[fin].len+1;
for(lpx=fin;lpx&&!s[lpx].tranc[ch];lpx=s[lpx].pre) s[lpx].tranc[ch]=npx;
if(!lpx) s[npx].pre=1;
else
{
lpy=s[lpx].tranc[ch];
if(s[lpy].len==s[lpx].len+1) s[npx].pre=lpy;
else
{
npy=++size;
s[npy]=s[lpy];
s[npy].len=s[lpx].len+1;
s[lpy].pre=s[npx].pre=npy;
while(s[lpx].tranc[ch]==lpy)
{
s[lpx].tranc[ch]=npy;
lpx=s[lpx].pre;
}
}
}
fin=npx;
}
void insert(char *str,int sl)
{
for(int i=1;i<=sl;i++)
ins(str[i]-'a');
}
}sam;
struct flandre
{
int ne[N][26],tmp[26];
void insert(char *s,int sl)
{
for(int i=sl;i>=0;i--)
memcpy(ne[i],tmp,104),tmp[s[i]-'a']=i;
}
}sem;
void solve1()
{
int ans=inf;
for(int sp=1;sp<=n1;sp++)
{
int px=1;
for(int i=sp;i<=n1;i++)
{
if(!sam.s[px].tranc[s1[i]-'a']){ans=min(ans,i-sp+1);break;}
px=sam.s[px].tranc[s1[i]-'a'];
}
}
printf("%d\n",ans==inf?-1:ans);
}
void solve2()
{
int ans=inf;
for(int sp=1;sp<=n1;sp++)
{
int px=0;
for(int i=sp;i<=n1;i++)
{
if(!sem.ne[px][s1[i]-'a']){ans=min(ans,i-sp+1);break;}
px=sem.ne[px][s1[i]-'a'];
}
}
printf("%d\n",ans==inf?-1:ans);
}
int dp[N<<1];
void solve3()
{
int ans=inf;
memset(dp,0x3f,sizeof(dp));
dp[1]=0;
for(int i=1;i<=n1;i++)
{
for(int x=sam.size;x;x--)
{
if(sam.s[x].tranc[s1[i]-'a']) dp[sam.s[x].tranc[s1[i]-'a']]=min(dp[sam.s[x].tranc[s1[i]-'a']],dp[x]+1);
else ans=min(ans,dp[x]+1);
}
}
printf("%d\n",ans==inf?-1:ans);
}
void solve4()
{
int ans=inf;
memset(dp,0x3f,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n1;i++)
{
for(int x=n2;x>=0;x--)
{
if(!sem.ne[x][s1[i]-'a']) ans=min(ans,dp[x]+1);
else dp[sem.ne[x][s1[i]-'a']]=min(dp[sem.ne[x][s1[i]-'a']],dp[x]+1);
}
}
printf("%d\n",ans==inf?-1:ans);
}
int Iris()
{
scanf("%s%s",s1+1,s2+1),n1=strlen(s1+1),n2=strlen(s2+1);
sam.insert(s2,n2),sem.insert(s2,n2);
solve1(),solve2(),solve3(),solve4();
return 0;
}
}
int main(){return RKK::Iris();}

bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp)的更多相关文章

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

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

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

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

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

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

  4. bzoj 4032 [ HEOI 2015 ] 最短不公共子串 —— 后缀自动机+序列自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4032 序列自动机其实就是每个位置记录一下某字母后面第一个出现位置,为了子序列能尽量长. 对字 ...

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

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

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

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

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

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

  8. 洛谷 P4112 [HEOI2015]最短不公共子串 解题报告

    P4112 [HEOI2015]最短不公共子串 题目描述 在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之. 一个串的"子串"指的是它的连续的一段,例如bcd是 ...

  9. BZOJ 4032: [HEOI2015]最短不公共子串

    4032: [HEOI2015]最短不公共子串 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 446  Solved: 224[Submit][Sta ...

随机推荐

  1. python的import语句

    1.import作用 import跟C/C++中的#include作用有点类似,都是为了调用定义在其他文件中的变量.函数或者类,但实现的区别很大. C/C++中如果a.cpp include了b.h那 ...

  2. 深入分析CVE-2021-4034及漏洞复现

    正向shell总结 一.winrm,http.sys(端口复用) 介绍 winrm WinRM全称是Windows Remote Management,是微软服务器硬件管理功能的一部分,能够对本地或远 ...

  3. Go内存逃逸分析

    Go的内存逃逸及逃逸分析 Go的内存逃逸 分析内存逃逸之前要搞清楚一件事 我们编写的程序中的函数和局部变量是存放在栈上的(补充一点堆上存储的数据的指针 是存放在栈上的 因为指针的大小是可以提前预知的 ...

  4. 用这个BI工具,不会代码的业务人员也能做数据分析!

    随着企业的迅速发展,企业对数据分析的需求也在不断地凸显,但我们在实际的工作中经常会遇到这样尴尬的情形:擅长数据分析的人不懂业务,擅长业务的人又不了解数据分析.那么怎么让更懂业务逻辑.业务分析需求和痛点 ...

  5. WPF 开发,优化 AvalonEdit 显示单行超长文本的性能。

    路遥工具箱内置了一个名为"JSON 格式化"的功能.通过该功能可以将 JSON 字符串进行美化和简化(设置缩进和取消缩进). 该功能上线后收到很多客户的反馈:大部分经由网络传输的J ...

  6. linux /etc/fstab 文件详细说明(整理版)

    转至:https://blog.csdn.net/xiaolongwang2010/article/details/8657332?utm_medium=distribute.pc_relevant. ...

  7. vue项目部署到IIS服务器上

    前端Vue项目需要部署到IIS服务器上: 准备工作: 1:部署IIS服务器 2:项目npm run build打包生成需要部署的文件(dist文件夹)我的是manage文件夹 开始部署: 1:复制文件 ...

  8. python面试_总结04_字符串练习题

    完成下列列表相关的编程题,先运行下列的test函数,在完成每道题之后,都可以通过调用test函数检测所写函数对错 def test(got, expected): if got == expected ...

  9. (第二章第二部分)TensorFlow框架之读取图片数据

    系列博客链接: (第二章第一部分)TensorFlow框架之文件读取流程:https://www.cnblogs.com/kongweisi/p/11050302.html 本文概述: 目标 说明图片 ...

  10. Java 中线程池的 7 种创建方式!

    在 Java 语言中,并发编程都是通过创建线程池来实现的,而线程池的创建方式也有很多种,每种线程池的创建方式都对应了不同的使用场景,总体来说线程池的创建可以分为以下两类: 通过 ThreadPoolE ...