bzoj 3796: Mushroom追妹纸 AC自动机+后缀自动机+dp
题目大意:
给定三个字符串s1,s2,s3,求一个字符串w满足:
- w是s1的子串
- w是s2的子串
- s3不是w的子串
- w的长度应尽可能大
题解:
首先我们可以用AC自动机找出s3在s1,s2中出现的位置(窝不会kmp)
不完全包括特定区间的最长公共子串了.
我们二分一下答案的长度k
于是我们发现问题变成了:
- 给定两个字符串,有一些点不能选择,问是否存在两个点所代表后缀的LCP >= k
所以我们将两个字符串拼接起来,有后缀自动机建立后缀树
然后在后缀树上O(n)dp一边便可处理
\(O(nlogn)\)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
namespace ACM{
const int maxn = 10010;
int ch[maxn][26],nodecnt;
bool danger[maxn];
inline void insert(char *s){
int nw = 0;
for(int i=0,c;s[i] != 0;++i){
c = s[i] - 'a';
if(ch[nw][c] == 0) ch[nw][c] = ++ nodecnt;
nw = ch[nw][c];
}danger[nw] = true;
}
int q[maxn],l,r,fail[maxn];
inline void build(){
l = 0;r = -1;fail[0] = 0;
for(int c=0;c<26;++c){
if(ch[0][c]){
fail[ch[0][c]] = 0;
q[++r] = ch[0][c];
}
}
while(l <= r){
int u = q[l++];
for(int c=0;c<26;++c){
int t = ch[fail[u]][c];
if(ch[u][c] == 0) ch[u][c] = t;
else{
fail[ch[u][c]] = t;
q[++r] = ch[u][c];
}
}
}
}
}
namespace Graph{
const int maxn = 210010;
struct Node{
int to,next;
}G[maxn];
int head[maxn],cnt;
void add(int u,int v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
}
}
namespace SAM{
const int maxn = 210010;
struct Node{
int nx[27];
int len,fa,x;
}T[maxn];
int last,nodecnt;
inline void init(){
T[last = nodecnt = 0].fa = -1;
}
inline void insert(char cha,int i){
int c = cha - 'a',cur = ++nodecnt,p;
T[cur].len = T[last].len + 1;
for(p = last;p != -1 && T[p].nx[c] == 0;p = T[p].fa) T[p].nx[c] = cur;
if(p == -1) T[cur].fa = 0;
else{
int q = T[p].nx[c];
if(T[q].len == T[p].len + 1) T[cur].fa = q;
else{
int co = ++ nodecnt;
T[co] = T[q];T[co].len = T[p].len + 1;
for(;p != -1 && T[p].nx[c] == q;p = T[p].fa) T[p].nx[c] = co;
T[cur].fa = T[q].fa = co;
}
}T[last = cur].x = i;
}
}
const int maxn = 210010;
char s1[maxn],s2[maxn],s3[maxn];
bool flag1[maxn],flag2[maxn];
int len1,len2,w,mid;
inline void work1(){
using namespace ACM;
int nw = 0;
for(int i=0;s1[i] != 0;++i){
nw = ch[nw][s1[i] - 'a'];
if(danger[nw]) flag1[i-w+1] = true;
}
nw = 0;
for(int i=0;s2[i] != 0;++i){
nw = ch[nw][s2[i] - 'a'];
if(danger[nw]) flag2[i-w+1] = true;
}
}
bool vis[maxn];
bool le[maxn],ri[maxn],both[maxn];
#define v G[i].to
inline bool dfs(int u,int f){
using namespace Graph;
using namespace SAM;
for(int i = head[u];i;i=G[i].next){
if(v == f) continue;
if(dfs(v,u)) return true;
if(le[v] && ri[v]) both[u] = true;
else le[u] |= le[v],ri[u] |= ri[v];
}
if(!vis[T[u].x]){
if(T[u].x < len1) le[u] = true;
if(T[u].x > len1) ri[u] = true;
}
if(T[u].len >= mid){
if(le[u] && ri[u]) return true;
if(le[u] && both[u]) return true;
if(ri[u] && both[u]) return true;
}
le[u] |= both[u];ri[u] |= both[u];
return false;
}
#undef v
inline bool check(){
for(int i=len1-1,c=0;i>=0;--i){
vis[i] = false;
if(flag1[i]) c = mid - w + 1;
if(c != 0) vis[i] = true,-- c;
}vis[len1] = true;
for(int i=len2-1,c=0;i>=0;--i){
vis[i+len1+1] = false;
if(flag2[i]) c = mid - w + 1;
if(c != 0) vis[i+len1+1] = true,--c;
}
for(int i=0;i<=SAM::nodecnt;++i) le[i] = ri[i] = both[i] = 0;
if(dfs(0,0)) return true;
return false;
}
int main(){
scanf("%s",s1);scanf("%s",s2);scanf("%s",s3);
ACM::insert(s3);ACM::build();
len1 = strlen(s1);len2 = strlen(s2);w = strlen(s3);
work1();SAM::init();
for(int i=len2-1;i>=0;--i) SAM::insert(s2[i],len1+i+1);SAM::insert('z'+1,len1);
for(int i=len1-1;i>=0;--i) SAM::insert(s1[i],i);
for(int i=1;i<=SAM::nodecnt;++i) Graph::add(SAM::T[i].fa,i);
int l = 0,r = len1,ans = 0;
while(l <= r){
mid = (l+r) >> 1;
if(check()) l = mid+1,ans = mid;
else r = mid-1;
}
printf("%d\n",ans);
getchar();getchar();
return 0;
}
bzoj 3796: Mushroom追妹纸 AC自动机+后缀自动机+dp的更多相关文章
- bzoj 3796: Mushroom追妹纸【二分+后缀数组+st表】
把三个串加上ASCII大于z的分隔符连起来,然后求SA 显然每个相同子串都是一个后缀的前缀,所以枚举s1的每个后缀的最长和s2相同的前缀串(直接在排序后的数组里挨个找,最近的两个分别属于s1和s2的后 ...
- [BZOJ 3796]Mushroom追妹纸
[BZOJ 3796]Mushroom追妹纸 题目 Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他 ...
- ●BZOJ 3796 Mushroom追妹纸
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3796 题解: 题意: 给出三个串 A,B,C 找出一个最长串 S, 使得 ...
- bzoj 3796 Mushroom追妹纸——后缀数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3796 长度一般都是 1e5 ,看这个是 5e4 ,一看就是把两个串接起来做. 自己本来想的是 ...
- bzoj 3796 Mushroom追妹纸 —— 后缀数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3796 先把三个串拼在一起,KMP 求 s1 , s2 中每个位置和 s3 的匹配情况: 注意 ...
- BZOJ 3796 Mushroom追妹纸 哈希+二分(+KMP)
先把两个串能匹配模式串的位置找出来,然后标记为$1$(标记在开头或末尾都行),然后对标记数组求一个前缀和,这样可以快速查到区间内是否有完整的一个模式串. 然后二分子串(答案)的长度,每次把长度为$md ...
- 【BZOJ3796】Mushroom追妹纸 二分+hash
[BZOJ3796]Mushroom追妹纸 Description Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决 ...
- [BZOJ3796]Mushroom追妹纸:后缀自动机+KMP
分析 这道题有个\(O(n)\)的后缀自动机做法,感觉很好理解就在这说一下. 先对\(s1\)和\(s2\)求最长公共子串,对于\(s2\)的每一个下标\(i\),求一个\(f[i]\)表示以\(s2 ...
- 【bzoj3796】Mushroom追妹纸 hash/sa+kmp+二分
Description Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意--写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他从网上找到了两篇极佳的情书, ...
随机推荐
- 软件测试之BUG分析定位概述(QA如何分析定位BUG)【转自 https://blog.csdn.net/kaka1121/article/details/51538979】
你是否遇到这样的场景? QA发现问题后找到DEV说: 不好了,你的程序出问题了! DEV(追查半小时之后): 唉,是你们测试环境配置的问题 唉,是你们数据不一致 唉,是你们**程序版本不对 唉,是** ...
- 洛谷P1038 神经网络==codevs1088 神经网络
P1038 神经网络 题目背景 人工神经网络(Artificial Neural Network)是一种新兴的具有自我学习能力的计算系统,在模式识别.函数逼近及贷款风险评估等诸多领域有广泛的应用.对神 ...
- Python闲谈(二)聊聊最小二乘法以及leastsq函数
1 最小二乘法概述 自从开始做毕设以来,发现自己无时无刻不在接触最小二乘法.从求解线性透视图中的消失点,m元n次函数的拟合,包括后来学到的神经网络,其思想归根结底全都是最小二乘法. 1-1 “多线→一 ...
- Convex combination
en.wikipedia.org/wiki/Convex_combination 凸组合 In convex geometry, a convex combination is a linear co ...
- 使用memcache进行账号验证服务
适用环境是需要频繁进行账号和请求合法性验证的地方 大致思路: 1.登陆时,服务器端接收一个账号和密码,还可以再加上用户的ip等信息通过md5等加密算法计算出一个定长的字符串作为用来验证的token 2 ...
- IO多路复用的作用?并列举实现机制以及区别?
I/O多路复用是用于提升效率,单个进程可以同时监听多个网络连接IO. 举例:通过一种机制,可以监视多个文件描述符,一旦描述符就绪(读就绪和写就绪),能通知程序进行相应的读写操作,I/O多路复用避免阻塞 ...
- 论文解析 "A Non-Local Cost Aggregation Method for Stereo Matching"
传统的使用窗口的方法缺陷主要在 1.窗口外的像素不能参与匹配判断. 2.在低纹理区域很容易产生错误匹配 论文的主要贡献在代价聚类上(左右图像带匹配点/区域的匹配代价计算),目标是图像内所有点都对该点传 ...
- 常见数据挖掘算法的Map-Reduce策略(2)
接着上一篇文章常见算法的mapreduce案例(1)继续挖坑,本文涉及到算法的基本原理,文中会大概讲讲,但具体有关公式的推导还请大家去查阅相关的文献文章.下面涉及到的数据挖掘算法会有:L ...
- python实例3-天气小模块
调用中国天气的一小段代码,抓取 #! /usr/bin/python # coding = utf-8 # ToDo: get weather info from weather.com.cn # A ...
- 海信电视 LED55K370 升级固件总结【含固件下载地址】
最早电视买回来,感觉垃圾软件太多,root后,删软件不小心删除了桌面,导致没桌面. 用ADB装了点软件,凑合可以用. 后来装了悟空遥控,然后装了沙发桌面,不影响使用了. 最近海信不停推送更新系统,改手 ...