bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp)
bzoj4032/luoguP4112 [HEOI2015]最短不公共子串(后缀自动机+序列自动机上dp)
题解时间
给两个小写字母串 $ 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)的更多相关文章
- BZOJ 4032: [HEOI2015]最短不公共子串 后缀自动机 暴力
4032: [HEOI2015]最短不公共子串 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4032 Description 在虐各种最 ...
- bzoj 4032 [HEOI2015]最短不公共子串——后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4032 不是 b 的子串的话就对 b 建后缀自动机,在 a 上枚举从每个位置开始的子串或者找子 ...
- BZOJ 4032: [HEOI2015]最短不公共子串(后缀自动机+记忆化搜索)
传送门 解题思路 首先需要预处理两个串\(nxt(i)(j)\)表示i位置之后最近的\(j\). 第一问直接对\(b\)建后缀自动机,枚举\(a\)的起点暴力匹配. 第二问枚举\(a\)的起点,\(b ...
- bzoj 4032 [ HEOI 2015 ] 最短不公共子串 —— 后缀自动机+序列自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4032 序列自动机其实就是每个位置记录一下某字母后面第一个出现位置,为了子序列能尽量长. 对字 ...
- 【BZOJ4032】[HEOI2015]最短不公共子串(后缀自动机,序列自动机)
[BZOJ4032][HEOI2015]最短不公共子串(后缀自动机,序列自动机) 题面 BZOJ 洛谷 题解 数据范围很小,直接暴力构建后缀自动机和序列自动机,然后直接在两个自动机上进行\(bfs\) ...
- luoguP4112 [HEOI2015]最短不公共子串 SAM,序列自动机,广搜BFS
luoguP4112 [HEOI2015]最短不公共子串 链接 luogu loj 思路 子串可以用后缀自动机,子序列可以用序列自动机. 序列自动机是啥,就是能访问到所有子序列的自动机. 每个点记录下 ...
- bzoj4032: [HEOI2015]最短不公共子串(SAM+DP)
4032: [HEOI2015]最短不公共子串 题目:传送门 题解: 陈年老题良心%你赛膜爆嘎爷 当初做题...一眼SAM...结果只会两种直接DP的情况... 情况1: 直接设f[i][j] 表示的 ...
- 洛谷 P4112 [HEOI2015]最短不公共子串 解题报告
P4112 [HEOI2015]最短不公共子串 题目描述 在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之. 一个串的"子串"指的是它的连续的一段,例如bcd是 ...
- BZOJ 4032: [HEOI2015]最短不公共子串
4032: [HEOI2015]最短不公共子串 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 446 Solved: 224[Submit][Sta ...
随机推荐
- Solution -「Ynoi 2018」「洛谷 P4117」五彩斑斓的世界
\(\mathcal{Description}\) Link. 给定序列 \(\{a_n\}\),处理 \(m\) 次操作: 给定 \(l,r,x\),把 \([l,r]\) 内所有 \(&g ...
- Solution -「洛谷 P4194」矩阵
\(\mathcal{Description}\) Link. 给定一个 \(n\times m\) 的矩阵 \(A\),构造一个 \(n\times m\) 的矩阵 \(B\),s.t. \ ...
- 第二章 初始MySQL 语法
1.使用MySQL的优势 运行速度快.MySQL体积小,命令执行的速度快: 使用成本低.MySQL是开源的. 容易使用. 可移植性强.MySQL能够运行于多种系统平台之上,windows,linux, ...
- CentOS7下修改默认网卡名为eth0的方法
1.修改网卡配置文件中的 DEVICE=参数的,关于eth0 [root@ansheng ~ ]# cd /etc/sysconfig/network-scripts/ [root@ansheng n ...
- 从Spring容器的角度理解Dubbo扩展点的加载时机
对于Dubbo提供的扩展点,主程序执行的过程中并没有显示调用加载的过程,无论是自激活的Filter还是自适应的ThreadPool.那么这样的扩展点在程序运行的哪个节点调用的呢?跟踪之前性能监控扩展点 ...
- seaborn学习笔记(四):箱型图、小提琴图
html { font-family: sans-serif; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100% } body { ...
- ios开发 Rsa签名 base64转码
因为公司要求做了一个加密 网上的资料少有可用的 于是我看到了一位大神的曙光 但是未介绍使用方法 然后另一位大神给予了使用方法 但是没有把库给出来 我整理了一下 希望大家看的有些启发 证书生成 ...
- [题解]hihoCoder挑战赛18——题目1 神奇字符串
题目地址:http://hihocoder.com/problemset/problem/1264 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 我们说两个字符串是非常 ...
- Renix中如何实现流调速——网络测试仪实操
在Renix操作中有时我们需要进行流调速,那么如何实现呢?接下来为您详细介绍. 第一步:预约测试资源 首先打开Renix软件,连接机箱, 预约端口 第二步:流调速 例如:端口下有3条流,分别设置为10 ...
- 【C# 】继承
背景..什么是继承? 「继承」是对象导向编程的其中一个基本属性. 它可让您定义子类,重复使用(继承).扩充或修改父类别行为. 其成员可供继承的类别称为基底类别. 继承基底类别成员的类别则称为「衍生类别 ...