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决定不手写情书.他从网上找到了两篇极佳的情书, ...
随机推荐
- 批量删除redis某个键值
/usr/local/redis/src/redis-cli -h 172.28.6.23 -p 6383 keys "virtual*" |xargs /usr/local/r ...
- maven;spring;pom
[说明]因为对环境配置文件理解的不充分,遇到问题经常是无法独自解决,特别是maven和javaweb的转换,也是糊里糊涂的,今天就又出问题了. [说明] 一:今日完成 1)任务二的效果展示看的我一脸懵 ...
- NSTheard 详解
一.什么是NSThread NSThread是基于线程使用,轻量级的多线程编程方法(相对GCD和NSOperation),一个NSThread对象代表一个线程, 需要手动管理线程的生命周期,处理线程同 ...
- information entropy as a measure of the uncertainty in a message while essentially inventing the field of information theory
https://en.wikipedia.org/wiki/Claude_Shannon In 1948, the promised memorandum appeared as "A Ma ...
- 常见数据挖掘算法的Map-Reduce策略(1)
大数据这个名词是被炒得越来越火了,各种大数据技术层出不穷,做数据挖掘的也跟着火了一把,呵呵,现今机器学习算法常见的并行实现方式:MPI,Map-Reduce计算框架,GPU方面,grap ...
- gsub! 和 gsub
ruby中带“!"和不带"!"的方法的最大的区别就是带”!"的会改变调用对象本身了.比方说str.gsub(/a/, 'b'),不会改变str本身,只会返回一个 ...
- Zookeeper启动Permission denied
Zookeeper 查询状态,出现如下问题: JMX enabled by default Using config: /usr/zookeeper/zookeeper-/bin/../conf/zo ...
- Data Structure Linked List: Flattening a Linked List
http://www.geeksforgeeks.org/flattening-a-linked-list/ #include <iostream> #include <vector ...
- 20145229吴姗珊 《Java程序设计》两天小总结
20145229吴姗珊 <Java程序设计>两天小总结 教材学习内容总结 第十章 输入\输出 1.java将输入\输出抽象化为串流,数据有来源及目的地,衔接两者的是串流对象 2.从应用程序 ...
- windows 2008 server 英文版 支持中文显示
1:打开Start menu(开始菜单)并单击Control Panel(控制面板)打开它 2:单击Clock, Language, and Region(时钟.语言和区域)下面的Change dis ...