这其实是道水题。。。

题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4032

(luogu)https://www.luogu.org/problemnew/show/P4112

题解:

Task 1

\(O(n^2)\)做法无数(也有不用SAM的\(O(n^2)\)做法),我讲一下我的做法。

直接对B串建后缀自动机,用A串在上面跑,而且是像求两个串的最长公共子串那样跑,如果遇到失配了就拿当前长度\(+1\)更新答案。但是要注意失配后当前的长度不能设成当前节点的\(len\)(最大长度),而应该是\(len[fail[u]]+1\)(最小长度)。

时间复杂度\(O(n)\).

由于没有在网上看到\(O(n)\)做法,所以此做法正确性未知(能过,但是数据很水,一开始写成\(len\)了依然能过10个点中的9个)。

Task 2

设\(nxt[i][j]\)表示B序列中第\(i\)个位置之后最靠前的字符\(j\)的位置。枚举A子串的起始位置,贪心即可。

时间复杂度\(O(n^2)\).

听说有人把这个东西称作“序列自动机”,感觉也有道理啊,这玩意确实像个自动机。

Task 3

子串就用后缀自动机,子序列就用“序列自动机”美滋滋。

设\(dp[i][j]\)表示A串前\(i\)个位置匹配B串后缀自动机的节点\(j\),最少用多少长度。如果能转移就转移,不能转移就用\(dp[i][j]+1\)更新答案。注意要在每个\(i\)都更新(因为子序列可以不到头)。

然后第一维可以像01背包一样省掉,我觉得第二维要按先儿子后父亲的顺序循环。但是网上有人直接从\(1\)到\(siz\)循环也能过?

注意\(dp\)数组要开两倍。

Task 4

设\(dp[i][j]\)表示A串前\(i\)个位置匹配B串前\(j\)个位置的最小长度。

转移同Task 3. 如果用一维数组,从\(n\)到\(1\)循环。

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std; const int N = 2000;
const int S = 26;
int len[(N<<1)+3];
int fa[(N<<1)+3];
int son[(N<<1)+3][S+3];
char a[N+3],b[N+3];
int pos[S+3];
int nxt[N+3][S+3];
int dp[(N<<1)+3];
int ord[(N<<1)+3];
int buc[N+3];
int n,m,siz,rtn,lstpos; void initSAM()
{
siz = rtn = lstpos = 1;
} void insertchar(char ch)
{
int p = lstpos,np; siz++; np = lstpos = siz; len[np] = len[p]+1;
for(; p && son[p][ch]==0; p=fa[p]) {son[p][ch] = np;}
if(!p) {fa[np] = rtn;}
else
{
int q = son[p][ch];
if(len[p]+1==len[q]) {fa[np] = q;}
else
{
siz++; int nq = siz; len[nq] = len[p]+1;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq] = fa[q]; fa[np] = fa[q] = nq;
for(; p && son[p][ch]==q; p=fa[p]) {son[p][ch] = nq;}
}
}
} void update(int &x,int y) {x = min(x,y);} int main()
{
initSAM();
scanf("%s",a+1); n = strlen(a+1); for(int i=1; i<=n; i++) a[i] -= 96;
scanf("%s",b+1); m = strlen(b+1); for(int i=1; i<=m; i++) b[i] -= 96;
for(int i=1; i<=m; i++)
{
insertchar(b[i]);
}
for(int i=1; i<=m; i++)
{
for(int j=pos[b[i]]; j<i; j++)
{
nxt[j][b[i]] = i;
}
pos[b[i]] = i;
}
for(int i=1; i<=S; i++)
{
for(int j=0; j<=m; j++) {if(!nxt[j][i]) nxt[j][i] = m+1;}
}
for(int i=1; i<=siz; i++) buc[len[i]]++;
for(int i=1; i<=n; i++) buc[i] += buc[i-1];
for(int i=siz; i>=1; i--) ord[buc[len[i]]--] = i;
//Question 1
int u = rtn,cur = 0,ans1 = m+1;
for(int i=1; i<=n; i++)
{
while(u && son[u][a[i]]==0) {ans1 = min(ans1,cur+1); u = fa[u]; cur = len[fa[u]]+1;}
if(son[u][a[i]]!=0) {cur++; u = son[u][a[i]];}
else {ans1 = 1; u = rtn; cur = 0;}
}
if(ans1==m+1) printf("-1\n");
else printf("%d\n",ans1);
//Question 2
int ans2 = n+1;
for(int i=1; i<=n; i++)
{
int j = 0;
for(int k=i; k<=n; k++)
{
if(nxt[j][a[k]]<=m)
{
j = nxt[j][a[k]];
}
else
{
ans2 = min(ans2,k-i+1);
}
}
}
if(ans2==n+1) printf("-1\n");
else printf("%d\n",ans2);
//Question 3
int ans3 = n+1;
for(int i=1; i<=siz; i++) dp[i] = n+1; dp[rtn] = 0;
for(int i=1; i<=n; i++)
{
for(int j=siz; j>=1; j--)
{
int u = ord[j];
if(son[u][a[i]])
{
update(dp[son[u][a[i]]],dp[u]+1);
}
else
{
update(ans3,dp[u]+1);
}
}
}
if(ans3==n+1) printf("-1\n");
else printf("%d\n",ans3);
//Question 4
int ans4 = n+1;
for(int i=1; i<=n; i++) dp[i] = n+1; dp[0] = 0;
for(int i=1; i<=n; i++)
{
for(int j=m; j>=0; j--)
{
if(nxt[j][a[i]]<=m)
{
update(dp[nxt[j][a[i]]],dp[j]+1);
}
else
{
update(ans4,dp[j]+1);
}
}
}
if(ans4==n+1) printf("-1\n");
else printf("%d\n",ans4);
return 0;
}

BZOJ 4032 Luogu P4112 [HEOI2015]最短不公共子串 (DP、后缀自动机)的更多相关文章

  1. BZOJ.4032.[HEOI2015]最短不公共子串(DP 后缀自动机)

    题目链接 1.求A的最短子串,它不是B的子串. 子串是连续的,对B建SAM,枚举起点,在SAM上找到第一个无法匹配点即可.O(n)用SAM能做吗..开始想错了. 2.求A的最短子串,它不是B的子序列. ...

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

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

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

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

  4. BZOJ4032 [HEOI2015]最短不公共子串 【后缀自动机 + 序列自动机 + dp】

    题目链接 BZOJ4032 题解 首先膜\(hb\) 空手切神题 一问\(hash\),二问枚举 三问\(trie\)树,四问\(dp\) 南二巨佬神\(hb\) 空手吊打自动机 \(orz orz ...

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

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

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

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

  7. BZOJ 4032: [HEOI2015]最短不公共子串 (dp*3 + SAM)

    转博客大法好 第4个子任务中,为什么只转移最近的一个位置,自己YY吧(多YY有益身体健康). #include <bits/stdc++.h> using namespace std; t ...

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

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

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

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

随机推荐

  1. YTU 2715: 函数---判断某年某月某日是这一年中的第几天

    2715: 函数---判断某年某月某日是这一年中的第几天 时间限制: 1 Sec  内存限制: 128 MB 提交: 380  解决: 155 题目描述 在主程序(main)中输入某年某月某日,例如2 ...

  2. 【Hnoi2010】Bzoj2002 Bounce & Codevs2333 弹飞绵羊

    Position: http://www.lydsy.com/JudgeOnline/problem.php?id=3143 http://codevs.cn/problem/2333/ Descri ...

  3. P5058 [ZJOI2004]嗅探器 tarjan割点

    这个题是tarjan裸题.最后bfs暴力找联通块就行.(一开始完全写错了竟然得了70分,题意都理解反了...这数据强度...) 题干: 题目描述 某军搞信息对抗实战演习,红军成功地侵入了蓝军的内部网络 ...

  4. P4111 [HEOI2015]小Z的房间 生成树计数

    这个题是生成树计数的裸题,中间构造基尔霍夫矩阵,然后构成行列式,再用高斯消元就行了.这里高斯消元有一些区别,交换两行行列式的值变号,且消元只能将一行的数 * k 之后加到别的行上. 剩下就没啥了... ...

  5. P3052 [USACO12MAR]摩天大楼里的奶牛Cows in a Skyscraper 状压dp

    这个状压dp其实很明显,n < 18写在前面了当然是状压.状态其实也很好想,但是有点问题,就是如何判断空间是否够大. 再单开一个g数组,存剩余空间就行了. 题干: 题目描述 A little k ...

  6. codevs地鼠游戏(贪心)

    1052 地鼠游戏  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description 王钢是一名学习成绩优异的学生,在平时的学习中,他 ...

  7. jeecg中列表查询数据关联其他表的显示

    1.A表字段:id,name;B表字段:id,name,fid(A表外键),现查询A表和B表的所有数据并且查询条件A,B都有,在前台页面list显示 2.后台方法: @RequestMapping(p ...

  8. MFC学习篇(一):用OpenCV显示视频

    首先是一些基础的步骤,如建立MFC应用,添加按钮等,博主主要参考了下面这篇文章,其中的前32步都是用OpenCV显示图片和视频所必须的,即通用的.由于LZ原来有配置OpenCV的基础,所以配制还是比较 ...

  9. 【洛谷2839/BZOJ2653】middle(主席树)

    题目: 洛谷2839 分析: 记\(s_i\)表示原序列中第\(i\)大的数. 考虑对于任意一个区间\([a,b]\),设它的中位数为\(s_m\),那么这个区间内大于等于\(s_m\)的数和小于\( ...

  10. zblog实现后台导航栏增加链接功能的最简单方法

    首先在ftp中找到这个目录   zb_system/admin/ 然后找到    admin_top.php      这个文件 再然后找到这行代码      <?php ResponseAdm ...