题解

我们对于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」最短不公共子串的更多相关文章

  1. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

  2. LOJ #2359. 「NOIP2016」天天爱跑步(倍增+线段树合并)

    题意 LOJ #2359. 「NOIP2016」天天爱跑步 题解 考虑把一个玩家的路径 \((x, y)\) 拆成两条,一条是 \(x\) 到 \(lca\) ( \(x, y\) 最近公共祖先) 的 ...

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

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

  4. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  5. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  6. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  7. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  8. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

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

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

随机推荐

  1. 给Java新手的一些建议——Java知识点归纳(Java基础部分)

    原文出处:CSDN邓帅 写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,主要是和一些Java基础知识点相关的,所以也希望能分享给刚刚入门的Java程序员和打算入Java开发这个行 ...

  2. Shell记录-Shell命令(文件查找)

    常见解压/压缩命令 tar文件格式解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!) .gz文件格式解压1:g ...

  3. gson转换对象为json字符串时对特殊字符编码的问题

    使用google的gson进行object和json的转换,如下: public static String object2json(Object obj) { Gson gson = new Gso ...

  4. bzoj千题计划115:bzoj1024: [SCOI2009]生日快乐

    http://www.lydsy.com/JudgeOnline/problem.php?id=1024 枚举横着切还是竖着切,一边儿分多少块 #include<cstdio> #incl ...

  5. 蓝桥杯 地宫寻宝 DFS 动态规划

    #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cstdl ...

  6. golang sql.DB

    数据库 sql.DB连接池需知: sql.DB内置连接池,连接不足时会自动创建新连接,新创建的连接使用sql.Open()时传入的dsn来构造. sql.DBClose时只会关闭连接池中的连接,未归还 ...

  7. github 新创建repositories

    1. 在github上新建repo 2. 找到改repo的地址,用命令git clone https://....,  拉取到本地 3. 打开一个单独的窗口,打开此文件夹 4. 创建自己的python ...

  8. 【专题】计数问题(排列组合,容斥原理,Prufer序列)

    [容斥原理] 对于统计指定排列方案数的问题,一个方案是空间中的一个元素. 定义集合x是满足排列中第x个数的限定条件的方案集合,设排列长度为S,则一共S个集合. 容斥原理的本质是考虑[集合交 或 集合交 ...

  9. C++中的二级指针和指针引用函数传参

    在函数的使用过程中,我们都明白传值和传引用会使实参的值发生改变.那么能够通过传指针改变指针所指向的地址吗? 在解决这个问题之前,也许我们应该先了解指针非常容易混淆的三个属性: ①.指针变量地址(&am ...

  10. HDU 4825 Xor Sum (裸字典树+二进制异或)

    题目链接 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将 ...