【LOJ】#2123. 「HEOI2015」最短不公共子串
题解
我们对于B串建出后缀自动机和序列自动机
对于问题1,枚举左端点然后跑后缀自动机,直到不能匹配作为这个左端点的答案
对于问题2,枚举左端点然后跑序列自动机,直到不能匹配
对于问题3,设f[i][j]表示第前i个字符匹配到后缀自动机上第j个点的最少步数,如果下一步走不了则更新答案
对于问题4,设f[i][j]表示前i个字符匹配到序列自动机上第j个点的最少步数,如果下一步走不了则更新答案
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#define enter putchar('\n')
#define space putchar(' ')
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
const int MOD = 1000000007;
char A[2005],B[2005];
int LA,LB;
int f[2005][4005];
struct SuffixAutoMaton{
struct SAM_node {
SAM_node *par,*nxt[26];
int len;
SAM_node *find_next(char c) {
if(nxt[c - 'a']) return nxt[c - 'a'];
else return NULL;
}
}pool[4005],*tail = pool,*root,*last;
SuffixAutoMaton() {
root = last = tail++;
}
void build(int l,int e) {
SAM_node *nowp = tail++,*p;
nowp->len = l;
for(p = last ; p && !p->nxt[e]; p = p->par) {
p->nxt[e] = nowp;
}
if(!p) nowp->par = root;
else {
SAM_node *q = p->nxt[e];
if(q->len == p->len + 1) nowp->par = q;
else {
SAM_node *copyq = tail++;
*copyq = *q;
copyq->len = p->len + 1;
q->par = nowp->par = copyq;
for( ; p && p->nxt[e] == q ; p = p->par) {
p->nxt[e] = copyq;
}
}
}
last = nowp;
}
int calc1(int st) {
SAM_node *p = root;
int res = 0;
for(int i = st ; i <= LA ; ++i) {
p = p->find_next(A[i]);
if(!p) break;
++res;
}
if(res == LA - st + 1) return LA + 1;
return res + 1;
}
int calc3() {
int m = tail - pool;
for(int i = 0 ; i <= LA ; ++i) {
for(int j = 1 ; j <= m ; ++j) {
f[i][j] = 0x7fffffff;
}
}
f[0][1] = 0;
int res = LA + 1;
for(int i = 1 ; i <= LA ; ++i) {
for(int j = 1 ; j <= m ; ++j) {
if(f[i - 1][j] != 0x7fffffff) {
f[i][j] = min(f[i - 1][j],f[i][j]);
SAM_node *p = pool[j - 1].find_next(A[i]);
if(!p) res = min(res,f[i - 1][j] + 1);
else f[i][p - pool + 1] = min(f[i][p - pool + 1],f[i][j] + 1);
}
}
}
return res;
}
}SAM;
struct LineAutoMaton {
int ch[2005][26],head[30],next[2005],tot,rt;
LineAutoMaton() {
rt = tot = 1;
for(int i = 0 ; i < 26 ; ++i) head[i] = 1;
}
void build(char c) {
++tot;next[tot] = head[c - 'a'];
for(int i = 0 ; i < 26 ; ++i) {
for(int j = head[i] ; j ; j = next[j]) {
if(!ch[j][c - 'a']) ch[j][c - 'a'] = tot;
else break;
}
}
head[c - 'a'] = tot;
}
int calc2(int st) {
int p = rt,L = 0;
for(int i = st ; i <= LA ; ++i) {
if(ch[p][A[i] - 'a']) {
p = ch[p][A[i] - 'a'];
++L;
}
else break;
}
if(L == LA - st + 1) return LA + 1;
return L + 1;
}
int calc4() {
for(int i = 0 ;i <= LA ; ++i) {
for(int j = 1 ; j <= tot ; ++j) {
f[i][j] = 0x7fffffff;
}
}
f[0][1] = 0;
int res = LA + 1;
for(int i = 1 ; i <= LA ; ++i) {
for(int j = 1 ; j <= tot ; ++j) {
if(f[i - 1][j] != 0x7fffffff) {
f[i][j] = min(f[i - 1][j],f[i][j]);
int p = ch[j][A[i] - 'a'];
if(!p) res = min(res,f[i - 1][j] + 1);
else f[i][p] = min(f[i - 1][j] + 1,f[i][p]);
}
}
}
return res;
}
}LAM;
void Init() {
scanf("%s",A + 1);
scanf("%s",B + 1);
LA = strlen(A + 1);LB = strlen(B + 1);
for(int i = 1 ; i <= LB ; ++i) {
SAM.build(i,B[i] - 'a');
LAM.build(B[i]);
}
}
void Solve1() {
int ans = LA + 1;
for(int i = 1 ; i <= LA ; ++i) {
ans = min(ans,SAM.calc1(i));
}
if(ans > LA) puts("-1");
else {out(ans),enter;}
}
void Solve2() {
int ans = LA + 1;
for(int i = 1 ; i <= LA ; ++i) {
ans = min(ans,LAM.calc2(i));
}
if(ans > LA) puts("-1");
else out(ans),enter;
}
void Solve3() {
int ans = SAM.calc3();
if(ans > LA) puts("-1");
else out(ans),enter;
}
void Solve4() {
int ans = LAM.calc4();
if(ans > LA) puts("-1");
else out(ans),enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve1();
Solve2();
Solve3();
Solve4();
}
【LOJ】#2123. 「HEOI2015」最短不公共子串的更多相关文章
- Loj #3056. 「HNOI2019」多边形
Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...
- LOJ #2359. 「NOIP2016」天天爱跑步(倍增+线段树合并)
题意 LOJ #2359. 「NOIP2016」天天爱跑步 题解 考虑把一个玩家的路径 \((x, y)\) 拆成两条,一条是 \(x\) 到 \(lca\) ( \(x, y\) 最近公共祖先) 的 ...
- luoguP4112 [HEOI2015]最短不公共子串 SAM,序列自动机,广搜BFS
luoguP4112 [HEOI2015]最短不公共子串 链接 luogu loj 思路 子串可以用后缀自动机,子序列可以用序列自动机. 序列自动机是啥,就是能访问到所有子序列的自动机. 每个点记录下 ...
- Loj #2192. 「SHOI2014」概率充电器
Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...
- Loj #3096. 「SNOI2019」数论
Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...
- Loj #3093. 「BJOI2019」光线
Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...
- Loj #3089. 「BJOI2019」奥术神杖
Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...
- Loj #2542. 「PKUWC2018」随机游走
Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...
- 【BZOJ4032】[HEOI2015]最短不公共子串(后缀自动机,序列自动机)
[BZOJ4032][HEOI2015]最短不公共子串(后缀自动机,序列自动机) 题面 BZOJ 洛谷 题解 数据范围很小,直接暴力构建后缀自动机和序列自动机,然后直接在两个自动机上进行\(bfs\) ...
随机推荐
- vue学习记录
vue中常用的指令 v-model 双向数据绑定,一般用于表单元素 v-for 对数组或对象进行循环操作,使用的是v-for <!-- 普通循环 --><li v-for=" ...
- 关于connect by 误区讲解,纯属个人心得和经验,有图有文字
本博客是自己在学习和工作途中的积累与总结,仅供自己参考,也欢迎大家转载,转载时请注明出处. http://www.cnblogs.com/king-xg/p/6927541.html 如果觉得对您有帮 ...
- 51nod 1181 质数中的质数
1181 质数中的质数(质数筛法) 题目来源: Sgu 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 如果一个质数,在质数列表中的编号也是质数,那么就称 ...
- 2015/12/12 考了PAT,又回来玩Python了。
上次写飞机大战的坑还没填完,然后就有好长时间没有更新博客了.可能大家在疑惑我在干什么... 其实不是有意暂停博客更新的,十一月学校里有两个考试要准备,然后有好多实验要做.平时的课余时间本来就不是很多了 ...
- python核心编程笔记——Chapter5
好吧,开始第五章习题: 5-2.又是老调重谈,raw_input这个函数真是非常麻烦,返回是str类型,没办法,只能在函数里面使用int内建.(就只是一道简单的两数相乘,哭了) #!/usr/bin/ ...
- 精心整理的十个必须要知道CSS+DIV技巧
1.css font的简写规则 当我们写字体样式的时候,我们也许会这样子写 font-size: 1em; line-height: 1.5em; font-weight: bold; font-s ...
- php 获取唯一字符串与文件扩展名函数
/** * 生成唯一字符串 * @return string */ function getUniqueStr(){ return md5(uniqid(microtime(true),true)); ...
- 利用Object.defineProperty 简化 Chrome插件本地存储操作
通常谷歌插件本地存储写法很别扭☹,如 chrome.storage.sync.get(null,function(data){ //todo console.log(data); }); 如果get ...
- 关于getsockname()/getpeername()函数第一次被调用得到0.0.0.0结果的说明
最近阅读UNIX网络编程第四章时,书本末尾介绍了两个函数getsockname()和getpeername(),可以用于获取服务器端和客户端的IP地址与端口,原本很简单的两个函数,过一眼即明白函数的用 ...
- [转]GCC常用参数详解
简介gcc and g++现在是gnu中最主要和最流行的c & c++编译器 .gcc/g++在执行编译工作的时候,总共需要以下几步:1.预处理,生成.i的文件[预处理器cpp]2.将预处理后 ...