题目描述

给出字符串s1、s2、s3,找出一个字符串w,满足:
1、w是s1的子串;
2、w是s2的子串;
3、s3不是w的子串。
4、w的长度应尽可能大
求w的最大长度。

输入

输入有三行,第一行为一个字符串s1第二行为一个字符串s2, 
第三行为一个字符串s3。输入仅含小写字母,字符中间不含空格。

输出

输出仅有一行,为w的最大可能长度,如w不存在,则输出0。

样例输入

abcdef
abcf
bc

样例输出

2


题解

Kmp+二分+Hash

先使用Kmp处理出s3在s1、s2中出现的所有位置,那么w的选择不能包含这些位置。

然后答案显然满足二分性质,因此二分答案,判断是否有s1和s2的公共长度为mid的子串。

将s1的所有长度为mid且不包含s3的子串的Hash值处理出来,放到哈希表中,然后将s2的所有长度为mid且不包含s3的子串的Hash值放到哈希表里查询即可。

其中判断是否包含s3的子串可以使用前缀后缀和:对于当前的[l,r],如果不合法,相当于在r前面出现过的右端点加上l后面出现过的左端点大于总数目。

Hash的过程可以直接使用自然溢出。

时间复杂度 $O(n\log n)$

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #define N 50010
  5. #define M 30000000
  6. using namespace std;
  7. typedef unsigned long long ull;
  8. ull base[N];
  9. int n[3] , next[N] , sa[2][N] , sb[2][N];
  10. char s[3][N];
  11. struct data
  12. {
  13. int head[M] , next[N] , tot;
  14. ull v[N];
  15. data() {tot = 0;}
  16. inline void insert(ull x)
  17. {
  18. if(!head[x % M]) head[x % M] = ++tot;
  19. else
  20. {
  21. int i;
  22. for(i = head[x % M] ; next[i] ; i = next[i]);
  23. next[i] = ++tot;
  24. }
  25. v[tot] = x;
  26. }
  27. inline bool count(ull x)
  28. {
  29. int i;
  30. for(i = head[x % M] ; i ; i = next[i])
  31. if(v[i] == x)
  32. return 1;
  33. return 0;
  34. }
  35. inline void clear()
  36. {
  37. int i;
  38. for(i = 1 ; i <= tot ; i ++ ) v[i] = next[i] = head[v[i] % M] = 0;
  39. tot = 0;
  40. }
  41. }mp;
  42. void kmp(int p)
  43. {
  44. int i , j;
  45. for(i = j = 0 ; i < n[p] ; i ++ )
  46. {
  47. base[i + 1] = base[i] * 233;
  48. while(~j && s[p][i] != s[2][j]) j = next[j];
  49. if(++j == n[2]) sa[p][i - j + 1] ++ , sb[p][i] ++ , j = next[j];
  50. }
  51. for(i = n[p] - 2 ; ~i ; i -- ) sa[p][i] += sa[p][i + 1];
  52. for(i = 1 ; i < n[p] ; i ++ ) sb[p][i] += sb[p][i - 1];
  53. }
  54. bool judge(int mid)
  55. {
  56. int i;
  57. ull v = 0;
  58. mp.clear();
  59. for(i = 0 ; i < mid - 1 ; i ++ ) v = v * 233 + s[0][i];
  60. for(i = mid - 1 ; i < n[0] ; i ++ )
  61. {
  62. v = v * 233 + s[0][i];
  63. if(sa[0][i - mid + 1] + sb[0][i] <= sa[0][0]) mp.insert(v);
  64. v -= s[0][i - mid + 1] * base[mid - 1];
  65. }
  66. v = 0;
  67. for(i = 0 ; i < mid - 1 ; i ++ ) v = v * 233 + s[1][i];
  68. for(i = mid - 1 ; i < n[1] ; i ++ )
  69. {
  70. v = v * 233 + s[1][i];
  71. if(sa[1][i - mid + 1] + sb[1][i] <= sa[1][0] && mp.count(v)) return 1;
  72. v -= s[1][i - mid + 1] * base[mid - 1];
  73. }
  74. return 0;
  75. }
  76. int main()
  77. {
  78. int i , j , l , r , mid , ans = 0;
  79. for(i = 0 ; i < 3 ; i ++ ) scanf("%s" , s[i]) , n[i] = strlen(s[i]);
  80. next[0] = -1;
  81. for(i = 1 , j = -1 ; i <= n[2] ; i ++ )
  82. {
  83. while(~j && s[2][j] != s[2][i - 1]) j = next[j];
  84. next[i] = ++j;
  85. }
  86. base[0] = 1 , kmp(0) , kmp(1);
  87. l = 1 , r = min(n[0] , n[1]);
  88. while(l <= r)
  89. {
  90. mid = (l + r) >> 1;
  91. if(judge(mid)) ans = mid , l = mid + 1;
  92. else r = mid - 1;
  93. }
  94. printf("%d\n" , ans);
  95. return 0;
  96. }

【bzoj3796】Mushroom追妹纸 Kmp+二分+Hash的更多相关文章

  1. BZOJ3796 Mushroom追妹纸(二分答案+后缀数组+KMP)

    求出一个串使得这个串是\(s1,s2\)的子串.串中不包含\(s3\). 如果没有这个\(s3\)就可以二分答案,然后height小于二分值分一组.看看每组里是不是出现过\(s1,s2\)的后缀.判断 ...

  2. BZOJ3796 Mushroom追妹纸 字符串 SA KMP

    原文链接https://www.cnblogs.com/zhouzhendong/p/9253173.html 题目传送门 - BZOJ3796 题意 找一个串 $w$ 满足: 1.$w$ 是 $s_ ...

  3. [BZOJ3796]Mushroom追妹纸:后缀自动机+KMP

    分析 这道题有个\(O(n)\)的后缀自动机做法,感觉很好理解就在这说一下. 先对\(s1\)和\(s2\)求最长公共子串,对于\(s2\)的每一个下标\(i\),求一个\(f[i]\)表示以\(s2 ...

  4. BZOJ3796 : Mushroom追妹纸

    将S1与S2用#号拼接在一起形成S串 将S3与S串跑KMP求出S3在S串中每次出现的位置l[i] 对于S串每个后缀i,求出f[i]表示该串不包含S3串的最长前缀 然后求出S串的后缀数组 先从小到大扫描 ...

  5. bzoj 3796: Mushroom追妹纸【二分+后缀数组+st表】

    把三个串加上ASCII大于z的分隔符连起来,然后求SA 显然每个相同子串都是一个后缀的前缀,所以枚举s1的每个后缀的最长和s2相同的前缀串(直接在排序后的数组里挨个找,最近的两个分别属于s1和s2的后 ...

  6. 【BZOJ3796】Mushroom追妹纸 二分+hash

    [BZOJ3796]Mushroom追妹纸 Description Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决 ...

  7. [BZOJ 3796]Mushroom追妹纸

    [BZOJ 3796]Mushroom追妹纸 题目 Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他 ...

  8. 【bzoj3796】Mushroom追妹纸 hash/sa+kmp+二分

    Description Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意--写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他从网上找到了两篇极佳的情书, ...

  9. 【bzoj3796】Mushroom追妹纸

    Portal -->bzoj3796 Description 给出字符串s1.s2.s3,找出一个字符串w,满足: 1.w是s1的子串: 2.w是s2的子串: 3.s3不是w的子串. ​ 求w的 ...

随机推荐

  1. 20155323刘威良第二次实验 Java面向对象程序设计

    20155323刘威良第二次实验 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 ...

  2. tkinter菜单图标,工具栏

    所用的图片: import tkinter as tk from tkinter import messagebox, filedialog, simpledialog, colorchooser f ...

  3. Centos7使用yum安装MySQL5.6的正确姿势

    centos自带的repo是不会自动更新每个软件的最新版本,所以无法通过yum方式安装MySQL的高级版本. 所以,即使使劲用yum -y install mysql mysql-server mys ...

  4. 初始CSS模板

    /*开始 初始CSS模板 开始*/ body, div, address, blockquote, iframe, ul, ol, dl, dt, dd, li, dl, h1, h2, h3, h4 ...

  5. 初探C#

    初探.NET底层原理 学习C#离不开.net平台,因为微软的开发平台真的是太强大了,它为每一个开发者都做了太多太多,但是我们不仅要知道怎么用,而且也应该知道其中的内部到底包含了什么.本篇文章不仅讲一些 ...

  6. GitHub 多人协作开发 三种方式:

    GitHub 多人协作开发 三种方式: 一.Fork 方式 网上介绍比较多的方式(比较大型的开源项目,比如cocos2d-x) 开发者 fork 自己生成一个独立的分支,跟主分支完全独立,pull代码 ...

  7. Google Chrome插件分享

    前言 浏览器是大家日常使用最多的工具之一,对于程序员来说,Google Chrome浏览器当然是大家优选的最爱之一.面对Chrome丰富的插件真的是爱不释手,如何把自己的Chrome调教成自己心仪的样 ...

  8. 【TCP_协议_socket接口】-jmeter

    1.ip 2.端口号 3.传入参数 4.告诉软件返回  最后以为是什么,不然就会报错 或者无限制的等待  查ascll 码表 启动接口的方法

  9. HPUX 配置zabbix开机自动启动

    1. 在/etc/rc.config.d目录下创建zabbixd文件,并增加以下内容:    #!/sbin/sh    # v1.0 ?zabbixd startup/kill config     ...

  10. HTML5+Bootstrap 学习笔记 4

    HTML5 <map> <area> 标签 <map> 标签定义客户端的图像映射.图像映射是带有可点击区域的图像. <area> 标签定义图像映射内部的 ...