题目大意:

给定三个字符串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的更多相关文章

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

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

  2. [BZOJ 3796]Mushroom追妹纸

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

  3. ●BZOJ 3796 Mushroom追妹纸

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3796 题解: 题意:    给出三个串 A,B,C    找出一个最长串 S,    使得 ...

  4. bzoj 3796 Mushroom追妹纸——后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3796 长度一般都是 1e5 ,看这个是 5e4 ,一看就是把两个串接起来做. 自己本来想的是 ...

  5. bzoj 3796 Mushroom追妹纸 —— 后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3796 先把三个串拼在一起,KMP 求 s1 , s2 中每个位置和 s3 的匹配情况: 注意 ...

  6. BZOJ 3796 Mushroom追妹纸 哈希+二分(+KMP)

    先把两个串能匹配模式串的位置找出来,然后标记为$1$(标记在开头或末尾都行),然后对标记数组求一个前缀和,这样可以快速查到区间内是否有完整的一个模式串. 然后二分子串(答案)的长度,每次把长度为$md ...

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

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

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

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

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

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

随机推荐

  1. php之 人员的权限管理

    1.想好权限管理的作用? 2.有什么权限内容? 3.既然有权限管理那么就会有管理员? 4.登录后每个人员的界面会是不一样的? 一.想好这个权限是什么? 就做一个就像是vip的功能,普通用户和vip用户 ...

  2. 记录-阿里云Oss文件上传

    public class OssUtil { /** * 上传图片 * @param file * @param request * @return */ public static Map<S ...

  3. ElasticSearch(二十)定位不合法的搜索及其原因

    GET /test_index/test_type/_validate/query?explain { "query": { "math": { "t ...

  4. 我的Android进阶之旅------>启动Activity的标准Action和标准Category

    Android内部提供了大量标准的Action和Category常量. 除了参考本文外,您还可以参考了以下链接: http://developer.android.com/reference/andr ...

  5. postgres=# psql -U postgres -h 127.0.0.1 -p 5432 -d dreamstart_dev -w

    postgres=# psql -U postgres -h 127.0.0.1 -p 5432 -d dreamstart_dev -wpostgres-# \dNo relations found ...

  6. IE11 for Windows 7 Enterprise With SP1 故障

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/jaminwm/article/details/29592027 这个故障非常诡异,卸载IE11也没实 ...

  7. 【Prometheus】第二篇---基本查询语法

    这几天忙着开发别的项目,今天抽空写一下Prometheus的查询语法 1,查看指标 直接输入指标名字就行了,grafana会自动补全 2,查看某个指标的使用率,比如cpu使用率 用到rate函数,ra ...

  8. 3.25课·········JavaScript的DOM操作

    1.DOM的基本概念 DOM是文档对象模型,这种模型为树模型:文档是指标签文档:对象是指文档中每个元素:模型是指抽象化的东西. 2.Window对象操作 一.属性和方法: 属性(值或者子对象): op ...

  9. 【LeetCode】数组排列问题(permutations)(附加next_permutation解析)

    描述 Given a collection of distinct integers, return all possible permutations. Example: Input: [1,2,3 ...

  10. Linux系统中UI库curse.h不存在问题——贪吃蛇为例

    1. 问题 大家在用Linux写程序时,大家会使用Linux gcc编译器中的头文件curse.h.但往往一般的发行版中都没有默认安装这个头文件,需要大家自行安装.最近遇到这个问题,如下: Red  ...