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

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 446  Solved: 224
[Submit][Status][Discuss]

Description

在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。

一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是。
一个串的“子序列”指的是它的可以不连续的一段,例如bde是abcdef的子串,但bdd不是。
下面,给两个小写字母串A,B,请你计算:
(1) A的一个最短的子串,它不是B的子串
(2) A的一个最短的子串,它不是B的子序列
(3) A的一个最短的子序列,它不是B的子串
(4) A的一个最短的子序列,它不是B的子序列

Input

有两行,每行一个小写字母组成的字符串,分别代表A和B。

Output

输出4行,每行一个整数,表示以上4个问题的答案的长度。如果没有符合要求的答案,输出-1.

Sample Input

aabbcc
abcabc

Sample Output

2
4
2
4

HINT

对于100%的数据,A和B的长度都不超过2000

 

Source

 

[Submit][Status][Discuss]

本来以为是HEOI2015的大水题,然后被小甜甜安利了一发序列自动机……

我等蒟蒻并不会此等算法,所以只好暴力喽!

拿到之后看到是四个答案,就分别考虑。

问题一 A的一个最短的子串,不是B的子串

这个比较简单哈,刺姐姐和任哥哥不约而同地给出了HASH做法——预先对B串的每个子串处理出HASH值,扔进哈希表里,然后暴力枚举A串的每个子串,查询是否在B中出现过,如果没有出现过,就可以用来更新答案。

然后蒟蒻的我表示并不会HASH此等算法,只好KMP暴力喽。每次枚举A串中的一个位置,作为其子串的左端点,记为$L$。此时我们希望查询所有以$L$作为左端点的A的子串,最短的一个不是B的子串的东东。这个就对A串的$[L,Len]$求next数组,拿B串跑一遍KMP就行了。时间复杂度$O(N^2)$。

问题二 A的一个最短的子串,不是B的子序列

这个非常简单哈,众神犇(除了我的所有人)一致给出了暴力做法。枚举A的子串的左端点,然后暴力检查至少以那个点作为右端点,该子串才不是B的子序列。时间复杂度$O(N^2)$。

问题三 A的一个最短的子序列,不是B的子串

这个也很简单哈,众神犇表示不直接序列自动机直接上就可以,但是蒟蒻的我依旧不会,只好写暴力了哈。

先取出B的所有子串,塞到Trie树里面去,总的节点数是$O(N^2)$,算了下内存有点吃紧,就用map<int,int>了。

然后在每个节点上记录一个标记mark,代表A串中最少选出几个字符,才能匹配到Trie上的这个节点来。这个直接DFS就可以得到了。

然后在在每个Trie树节点上枚举一个字符,如果该节点没有这个字符的出边,那么A串就有机会找出一个合法的解了。此时我们只需要知道A串在mark位置之后是否出现过字符c即可,这个很简单喽。

问题四 A的一个最短的子序列,不是B的子序列

这个最最简单哈,只要用$f_{i,j}$表示使用A的前$i$个字符,使得B不得不使用前$j$个字符和其匹配,所能使用的最少字符数。这个$O(N^2)$动态规划,太简单就不说了。

然后顺利用四种暴力水过HEOI2015的最水一题。

  1. #include <map>
  2. #include <cstdio>
  3. #include <cstring>
  4.  
  5. #define chr char
  6. #define rst register
  7. #define rnt register int
  8.  
  9. template <class T>
  10. inline T min(const T &a, const T &b)
  11. {
  12. return a < b ? a : b;
  13. }
  14.  
  15. template <class T>
  16. inline T max(const T &a, const T &b)
  17. {
  18. return a > b ? a : b;
  19. }
  20.  
  21. #define mxn 2005
  22. #define mxm 4000005
  23.  
  24. int n, m;
  25.  
  26. chr a[mxn];
  27. chr b[mxn];
  28.  
  29. namespace case1
  30. {
  31. int tot;
  32. int pos;
  33. int vis[mxn];
  34. int fil[mxn];
  35. int nxt[mxn][];
  36.  
  37. inline int solve(int s)
  38. {
  39. tot = ;
  40. pos = ;
  41.  
  42. memset(vis, , sizeof vis);
  43. memset(nxt, , sizeof nxt);
  44. memset(fil, , sizeof fil);
  45.  
  46. for (rnt i = s; i < n; ++i)
  47. pos = nxt[pos][a[i] - 'a'] = ++tot;
  48.  
  49. fil[] = ;
  50.  
  51. for (rnt i = ; i < ; ++i)
  52. if (nxt[][i])
  53. fil[nxt[][i]] = ;
  54. else
  55. nxt[][i] = ;
  56.  
  57. for (rnt i = ; i <= tot; ++i)
  58. for (rnt j = ; j < ; ++j)
  59. if (nxt[i][j])
  60. fil[nxt[i][j]] = nxt[fil[i]][j];
  61. else
  62. nxt[i][j] = nxt[fil[i]][j];
  63.  
  64. pos = ;
  65.  
  66. for (rnt i = ; i < m; ++i)
  67. vis[pos = nxt[pos][b[i] - 'a']] = ;
  68.  
  69. for (rnt i = ; i <= tot; ++i)
  70. if (!vis[i])return i - ;
  71.  
  72. return 1E9;
  73. }
  74.  
  75. inline void main(void)
  76. {
  77. int ans = 1E9;
  78.  
  79. for (rnt i = ; i < n; ++i)
  80. ans = min(ans, solve(i));
  81.  
  82. if (ans != 1E9)
  83. printf("%d\n", ans);
  84. else
  85. printf("%d\n", -);
  86. }
  87. }
  88.  
  89. namespace case2
  90. {
  91. inline int solve(int s)
  92. {
  93. for (rnt i = s, j = ; i < n; ++i, ++j)
  94. {
  95. while (j < m && b[j] != a[i])
  96. ++j;
  97.  
  98. if (j >= m)
  99. return i - s + ;
  100. }
  101.  
  102. return 1E9;
  103. }
  104.  
  105. inline void main(void)
  106. {
  107. int ans = 1E9;
  108.  
  109. for (rnt i = ; i < n; ++i)
  110. ans = min(ans, solve(i));
  111.  
  112. if (ans != 1E9)
  113. printf("%d\n", ans);
  114. else
  115. printf("%d\n", -);
  116. }
  117. }
  118.  
  119. namespace case3
  120. {
  121. int nxt[mxn][];
  122.  
  123. inline void prework(void)
  124. {
  125. for (rnt i = ; i <= n; ++i)
  126. for (rnt j = ; j < ; ++j)
  127. nxt[i][j] = n;
  128.  
  129. for (rnt i = ; i < n; ++i)
  130. nxt[i][a[i] - 'a'] = i;
  131.  
  132. for (rnt i = n - ; i >= ; --i)
  133. for (rnt j = ; j < ; ++j)
  134. nxt[i][j] = min(nxt[i][j], nxt[i + ][j]);
  135. }
  136.  
  137. typedef std::map<int, int> map;
  138. typedef std::map<int, int>::iterator itr;
  139.  
  140. int tot = ;
  141. int mrk[mxm];
  142. map son[mxm];
  143.  
  144. inline void build(void)
  145. {
  146. for (rnt i = ; i < m; ++i)
  147. {
  148. rnt t = ;
  149.  
  150. for (rnt j = i; j < m; ++j)
  151. {
  152. rnt c = b[j] - 'a';
  153.  
  154. if (son[t][c] == )
  155. son[t][c] = ++tot;
  156.  
  157. t = son[t][c];
  158. }
  159. }
  160. }
  161.  
  162. int ans = 1E9;
  163.  
  164. inline void getmark(int t = , int d = )
  165. {
  166. if (d >= ans)return;
  167.  
  168. int p = mrk[t];
  169.  
  170. for (rnt i = ; i < ; ++i)
  171. if (nxt[p][i] < n) {
  172. if (son[t][i])
  173. mrk[son[t][i]] = nxt[p][i] + ,
  174. getmark(son[t][i], d + );
  175. else
  176. ans = min(ans, d);
  177. }
  178. }
  179.  
  180. inline void main(void)
  181. {
  182. build();
  183.  
  184. prework();
  185.  
  186. getmark();
  187.  
  188. if (ans != 1E9)
  189. printf("%d\n", ans);
  190. else
  191. printf("%d\n", -);
  192. }
  193. }
  194.  
  195. namespace case4
  196. {
  197. int nxt[mxn][];
  198.  
  199. int len[mxn][mxn];
  200.  
  201. inline void main(void)
  202. {
  203. for (rnt i = ; i <= m; ++i)
  204. for (rnt j = ; j < ; ++j)
  205. nxt[i][j] = m;
  206.  
  207. for (rnt i = ; i < m; ++i)
  208. nxt[i][b[i] - 'a'] = i;
  209.  
  210. for (rnt i = m - ; i >= ; --i)
  211. for (rnt j = ; j < ; ++j)
  212. nxt[i][j] = min(nxt[i][j], nxt[i + ][j]);
  213.  
  214. memset(len, 0x3f, sizeof len);
  215.  
  216. len[][] = ;
  217.  
  218. rnt t;
  219.  
  220. for (rnt i = ; i < n; ++i)
  221. for (rnt j = ; j <= m; ++j)
  222. if (len[i][j] < 0x3f3f3f3f) {
  223. t = nxt[j][a[i] - 'a'] + ;
  224. len[i + ][j] = min(len[i + ][j], len[i][j]);
  225. len[i + ][t] = min(len[i + ][t], len[i][j] + );
  226. }
  227.  
  228. int ans = 1E9;
  229.  
  230. for (rnt i = ; i <= n; ++i)
  231. ans = min(ans, len[i][m + ]);
  232.  
  233. if (ans != 1E9)
  234. printf("%d\n", ans);
  235. else
  236. printf("%d\n", -);
  237. }
  238. }
  239.  
  240. signed main(void)
  241. {
  242. #ifndef ONLINE_JUDGE
  243. freopen("in", "r", stdin);
  244. freopen("out", "w", stdout);
  245. #endif
  246.  
  247. scanf("%s", a); n = strlen(a);
  248. scanf("%s", b); m = strlen(b);
  249.  
  250. case1::main();
  251. case2::main();
  252. case3::main();
  253. case4::main();
  254. }

@Author: YouSiki

BZOJ 4032: [HEOI2015]最短不公共子串的更多相关文章

  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]最短不公共子串(DP 后缀自动机)

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

  4. bzoj 4032: [HEOI2015]最短不公共子串【dp+SAM】

    第一.二问: 就是最小的最长公共长度+1,设f[i][j]为a匹配到i,b匹配到j,第一问的转移是f[i][j]=(a[i]==b[j]?f[i-1][j-1]+1:0),第二问的转移是f[i][j] ...

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

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

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

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

  7. 【BZOJ】4032: [HEOI2015]最短不公共子串(LibreOJ #2123)

    [题意]给两个小写字母串A,B,请你计算: (1) A的一个最短的子串,它不是B的子串 (2) A的一个最短的子串,它不是B的子序列 (3) A的一个最短的子序列,它不是B的子串 (4) A的一个最短 ...

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

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

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

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

随机推荐

  1. HNOI2019 多边形 polygon

    HNOI2019 多边形 polygon https://www.luogu.org/problemnew/show/P5288 这题镪啊... 首先堆结论: 显然终止状态一定是所有边都连向n了 根据 ...

  2. hibernate 解决 java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration

    参考:https://stackoverflow.com/questions/9851528/java-lang-noclassdeffounderror-org-hibernate-cfg-conf ...

  3. windows下pwd、ls、tail-f命令使用

    一.问题 习惯了linux命令,在windows上使用cmd没有这些命令时很不习惯. 二.解决办法 2.1 找到这些命令对应的windows命令 ls,对应于windows的dir pwd,对应于wi ...

  4. TDD、BDD、ATDD、DDD 软件开发模式

    TDD.BDD.ATDD.DDD 软件开发模式 四个开发模式意思: TDD:测试驱动开发(Test-Driven Development) BDD:行为驱动开发(Behavior Driven Dev ...

  5. [朴孝敏][Ooh La La]

    歌词来源:http://music.163.com/#/song?id=484058960 作曲 : Damon Sharpe/Jimmy Burney/Adam Kapit [作曲 : Damon ...

  6. curator 分布式锁InterProcessMutex

    写这篇文章的目的主要是为了记录下自己在zookeeper 锁上踩过的坑,以及踩坑之后自己的一点认识; 从zk分布式锁原理说起,原理很简单,大家也应该都知道,简单的说就是zookeeper实现分布式锁是 ...

  7. linux-文件流4种读取方式

    第二种方式 第三种 第四种: 小括号在管道符的右边开辟了两个子进程 大括号在管道符的右边开辟了一个子进程, export 用来导出子进程的 num 还可以借助外部文件进行 七步扩展:

  8. PAT甲级题解(慢慢刷中)

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6102219.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  9. THE First Individual Project - Word frequency program

    第一次写博客,这次也是本学期写到第一个程序. 老师要求网址:http://www.cnblogs.com/jiel/p/3311400.html#2777556 一.项目预计时间 一开始想使用不熟悉的 ...

  10. Week7阅读笔记

    关于银弹: Brooks在他最著名的这篇文章里指出,在软件开发过程里是没有万能的终杀性武器的,只有各种方法综合运用,才是解决之道.而各种声称如何如何神奇的理论或方法,都不是能杀死“软件危机”这头人狼的 ...