题目描述

给出字符串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)$

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 50010
#define M 30000000
using namespace std;
typedef unsigned long long ull;
ull base[N];
int n[3] , next[N] , sa[2][N] , sb[2][N];
char s[3][N];
struct data
{
int head[M] , next[N] , tot;
ull v[N];
data() {tot = 0;}
inline void insert(ull x)
{
if(!head[x % M]) head[x % M] = ++tot;
else
{
int i;
for(i = head[x % M] ; next[i] ; i = next[i]);
next[i] = ++tot;
}
v[tot] = x;
}
inline bool count(ull x)
{
int i;
for(i = head[x % M] ; i ; i = next[i])
if(v[i] == x)
return 1;
return 0;
}
inline void clear()
{
int i;
for(i = 1 ; i <= tot ; i ++ ) v[i] = next[i] = head[v[i] % M] = 0;
tot = 0;
}
}mp;
void kmp(int p)
{
int i , j;
for(i = j = 0 ; i < n[p] ; i ++ )
{
base[i + 1] = base[i] * 233;
while(~j && s[p][i] != s[2][j]) j = next[j];
if(++j == n[2]) sa[p][i - j + 1] ++ , sb[p][i] ++ , j = next[j];
}
for(i = n[p] - 2 ; ~i ; i -- ) sa[p][i] += sa[p][i + 1];
for(i = 1 ; i < n[p] ; i ++ ) sb[p][i] += sb[p][i - 1];
}
bool judge(int mid)
{
int i;
ull v = 0;
mp.clear();
for(i = 0 ; i < mid - 1 ; i ++ ) v = v * 233 + s[0][i];
for(i = mid - 1 ; i < n[0] ; i ++ )
{
v = v * 233 + s[0][i];
if(sa[0][i - mid + 1] + sb[0][i] <= sa[0][0]) mp.insert(v);
v -= s[0][i - mid + 1] * base[mid - 1];
}
v = 0;
for(i = 0 ; i < mid - 1 ; i ++ ) v = v * 233 + s[1][i];
for(i = mid - 1 ; i < n[1] ; i ++ )
{
v = v * 233 + s[1][i];
if(sa[1][i - mid + 1] + sb[1][i] <= sa[1][0] && mp.count(v)) return 1;
v -= s[1][i - mid + 1] * base[mid - 1];
}
return 0;
}
int main()
{
int i , j , l , r , mid , ans = 0;
for(i = 0 ; i < 3 ; i ++ ) scanf("%s" , s[i]) , n[i] = strlen(s[i]);
next[0] = -1;
for(i = 1 , j = -1 ; i <= n[2] ; i ++ )
{
while(~j && s[2][j] != s[2][i - 1]) j = next[j];
next[i] = ++j;
}
base[0] = 1 , kmp(0) , kmp(1);
l = 1 , r = min(n[0] , n[1]);
while(l <= r)
{
mid = (l + r) >> 1;
if(judge(mid)) ans = mid , l = mid + 1;
else r = mid - 1;
}
printf("%d\n" , ans);
return 0;
}

【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. L012-linux系统文件属性知识深入详解小结

    L012-linux系统文件属性知识深入详解小结 最近的学习重点不在这上面,所以更新的比较慢,再加上母亲住院,感情问题,一系列吧,愿快点度过这黑色的4月份,希望我能在5月份阳光起来,加油! 回归正题 ...

  2. Linux 内核3.10.5 专场

    今天本人十分靠谱地下载了linux 内核的3.10.5版本,这个版本是最新的稳定版. 听路飞大虾(哪个路飞?就是那个戴草帽的橡胶小伙,航海很多时候都很空闲的,于是最近他也开始研读linux 内核了.) ...

  3. pytest使用笔记(三)——pytest+allure+jenkins配置使用

    按照pytest使用笔记(二)把pytest+allure配置好后,现在在jenkins配置好,先实现手动构建(立个小目标) 一,安装jenkins插件 首页->系统管理->插件管理,从“ ...

  4. 一学就会pip换镜像源

    首先介绍一个国内好用的镜像站 阿里云 http://mirrors.aliyun.com/pypi/simple/ 豆瓣 http://pypi.douban.com/simple/ 清华大学 htt ...

  5. 【snmp】Linux开启snmp及查询

    1.Linux snmp 1.安装snmp yum install -y net-snmp* 2.备份snmp配置 cp /etc/snmp/snmpd.conf /etc/snmp/snmpd.co ...

  6. [C++基础] tips

    1. 在g++ 中使支持C++11 https://askubuntu.com/questions/773283/how-do-i-use-c11-with-g This you can do by ...

  7. spring-boot-mybatis搭建

    写在开始 mybatis是一个持久化框架,支持手动sql.存储过程.高级映射.mybatis支持XML方式或注解方式将POJO与数据库表间建立映射. maven依赖 spring-boot.mysql ...

  8. 作业 20181120-3 Beta发布

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2408 小组介绍 组长:付佳 组员:张俊余 李文涛 孙赛佳 田良 于洋 段 ...

  9. scrum立会报告+燃尽图(第二周第六次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2251 一.小组介绍 组名:杨老师粉丝群 组长:乔静玉 组员:吴奕瑶.公冶 ...

  10. 关于解决乱码问题的一点探索之一(涉及utf-8和GBK)

    在使用Visual Studio 2005进行MFC开发的时候,发现自动添加的注释变成了乱码.像这样: // TODO: ÔÚ´ËÌí¼ÓרÓôúÂëºÍ/»òµ÷ÓûùÀà 还有这样: // ...