Portal -->bzoj3796

Description

  给出字符串s1、s2、s3,找出一个字符串w,满足:

  1、w是s1的子串;

  2、w是s2的子串;

  3、s3不是w的子串。

​  求w的最大长度。

​  数据范围:s1,s2长度<=50000,s3长度<=10000,字符都是小写字母

Solution

​  这题。。有非常优秀的蛤希做法,有非常优秀的SAM做法,也有非常优秀的直接用后缀数组然后不用其他的东西的做法

  但是

​  我比较菜就写了一个后缀数组+KMP+二分 == 并且一开始看错题了。。最后写了4k ==

​  那为啥还贴上来呢。。其实主要是纪念一下自己在经历了长达一年的后缀数组恐惧症之后终于在场上用SA搞了一道题。。(虽然说少打了一个\(-1\)少了\(10\)分qwq)

  (不过话说回来好像。。几种不同的做法只是。。实现不同而已。。大体思路都差不多。。然而别人写的优秀很多qwq)

  首先前两个条件直接把s1和s2拼起来中间加个分隔符(新串记为s)然后跑个\(sa\)就好了

  然后。。第三个条件的话(注意是s3不是w的子串!不是反过来。。==)我们考虑因为题目要求的是最大长度,那么显然应该是从\(rk\)最近的两个s1和s2的后缀的lcp中截取前面的一段使得这段中没有s3

​  那个lcp很好搞,维护一个\(pre[1/2][i]\)就表示排名为\(i\)的后缀的前一个s1/s2的后缀的排名就好了,然后没有s3的话我们可以先把s3当模式串,在s上跑一个KMP,这样就可以找出s中出现s3的位置(记录在\(rec\)数组中,\(rec[i]=0/1\)表示的是\(i\)这个位置是否是s3出现的结尾)然后把这个数组前缀和一下我们就可以快速判断出一个\(s[l...r]\)这个子串中是否出现了s3,如果出现了的话我们再二分一下,找到一个更前的结束位置\(r1\)满足\(s[l...r1]\)中没有出现s3,然后用\(r1-l+1\)更新答案,否则直接用\(r-l+1\)更新答案

  然后我二分的\(ans\)初值赋成了\(l\)少了\(10\)分。。是时候换个二分的写法了qwq

  

  代码大概长这个样子

//Sa::nxt这个数组是无用的。。之前看错题打上去的。。后面懒得删了qwq
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int SA=50000*2+10010,TOP=20,N=50010,inf=2147483647;
char s1[N],s2[N],s3[N],s[SA];
int ed[3],nxt[N],rec[N];
int n,m,len1,len2,len3,lens;
namespace Sa{/*{{{*/
int a[SA],b[SA],c[SA],sa[SA],rk[SA],height[SA];
int num[SA],which[SA];
int mn[SA][TOP+1];
int pre[3][SA],nxt[3][SA];
int n,mx;
bool cmp(int x,int y,int len,int *r)
{return r[x]==r[y]&&r[x+len]==r[y+len];}
void sort(int n){
for (int i=0;i<=mx;++i) c[i]=0;
for (int i=1;i<=n;++i) c[a[b[i]]]++;
for (int i=1;i<=mx;++i) c[i]+=c[i-1];
for (int i=n;i>=1;--i) sa[c[a[b[i]]]--]=b[i];
}
void get_sa(int _n){
mx=0; n=_n;
for (int i=1;i<=n;++i) a[i]=s[i]-'a'+1,b[i]=i,mx=max(mx,a[i]);
sort(n);
int cnt=0;
for (int len=1;cnt<n;len<<=1){
cnt=0;
for (int i=n-len+1;i<=n;++i) b[++cnt]=i;
for (int i=1;i<=n;++i)
if (sa[i]>len)
b[++cnt]=sa[i]-len;
sort(n);
swap(a,b);
cnt=1; a[sa[1]]=1;
for (int i=2;i<=n;a[sa[i++]]=cnt)
if (!cmp(sa[i-1],sa[i],len,b)) ++cnt;
mx=cnt;
}
}
void rmq(){
for (int i=1;i<=n;++i) mn[i][0]=height[i];
for (int j=1;j<=TOP;++j)
for (int i=n-(1<<j)+1;i>=1;--i)
if (mn[i][j-1]<mn[i+(1<<j-1)][j-1])
mn[i][j]=mn[i][j-1];
else
mn[i][j]=mn[i+(1<<j-1)][j-1];
}
void get_height(){
for (int i=1;i<=n;++i) rk[sa[i]]=i;
int k=0;
for (int i=1;i<=n;++i){
if (k) --k;
while (s[i+k]==s[sa[rk[i]-1]+k]) ++k;
height[rk[i]]=k;
}
rmq();
}
int lcp(int x,int y){
if (x==y)return ed[which[x]]-sa[x]+1;
if (x>y) swap(x,y);
int mnlen=min(ed[which[x]]-sa[x]+1,ed[which[y]]-sa[y]+1);
++x;
int len=y-x+1,lg=(int)(log(1.0*len)/log(2.0)); if (mn[x][lg]<mn[y-(1<<lg)+1][lg]) return min(mn[x][lg],mnlen);
return min(mn[y-(1<<lg)+1][lg],mnlen);
}
void prework(){
for (int i=1;i<=n;++i){
if (sa[i]<=len1) which[i]=1;
else if (len1+2<=sa[i]&&sa[i]<=len1+len2+1) which[i]=2;
else which[i]=3;
}
ed[1]=len1; ed[2]=len1+len2+1;
int pre1=-1,pre2=-1;
for (int i=1;i<=n;++i) pre[1][i]=pre[2][i]=0,nxt[1][i]=nxt[2][i]=n+1;
for (int i=1;i<=n;++i){
if (pre1!=-1) pre[1][i]=pre1;
if (pre2!=-1) pre[2][i]=pre2;
if (which[i]==1) pre1=i;
else pre2=i;
}
for (int i=n;i>=1;--i){
if (pre1!=-1) nxt[1][i]=pre1;
if (pre2!=-1) nxt[2][i]=pre2;
if (which[i]==1) pre1=i;
else pre2=i;
}
}
}/*}}}*/
void get_nxt(){
nxt[1]=0;
int j=0;
for (int i=2;i<=len3;++i){
while (j!=0&&s3[j+1]!=s3[i]) j=nxt[j];
if (s3[j+1]==s3[i]) ++j;
nxt[i]=j;
}
}
void kmp(){
int j=0;
for (int i=1;i<=lens;++i){
while (j!=0&&s3[j+1]!=s[i]) j=nxt[j];
if (s3[j+1]==s[i]) ++j;
if (j==len3){rec[i]=1;j=nxt[j];}
}
for (int i=1;i<=lens;++i)rec[i]+=rec[i-1];
}
int query(int l,int r){
if (l>r) return 0;
return rec[r]-rec[l-1];
}
int find(int l,int r){
int ans=l-1,mid=0,st=l;
while (l<=r){
mid=l+r>>1;
if (query(st,mid)>=1) r=mid-1;
else ans=mid,l=mid+1;
}
return ans;
}
void solve(){
int ans=0,tmp,num;
for (int i=1;i<=lens;++i){
if (s[Sa::sa[i]]=='z'+1) continue;
num=Sa::which[i]==1?2:1;
tmp=Sa::lcp(Sa::pre[num][i],i);
if (query(Sa::sa[i]+len3-1,Sa::sa[i]+tmp-1)>=1){
tmp=find(Sa::sa[i]+len3-1,Sa::sa[i]+tmp-1);
tmp=tmp-Sa::sa[i]+1;
}
ans=max(ans,tmp);
}
printf("%d\n",ans);
} int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%s",s1+1); len1=strlen(s1+1);
scanf("%s",s2+1); len2=strlen(s2+1);
scanf("%s",s3+1); len3=strlen(s3+1);
lens=0;
for (int i=1;i<=len1;++i) s[++lens]=s1[i];
s[++lens]='z'+1;
for (int i=1;i<=len2;++i) s[++lens]=s2[i];
Sa::get_sa(lens);
Sa::prework();
Sa::get_height();
get_nxt();
kmp(); solve();
}

【bzoj3796】Mushroom追妹纸的更多相关文章

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

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

  2. BZOJ3796 : Mushroom追妹纸

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

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

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

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

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

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

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

  6. [BZOJ 3796]Mushroom追妹纸

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

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

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

  8. 【bzoj3796】Mushroom追妹纸 Kmp+二分+Hash

    题目描述 给出字符串s1.s2.s3,找出一个字符串w,满足: 1.w是s1的子串: 2.w是s2的子串: 3.s3不是w的子串. 4.w的长度应尽可能大 求w的最大长度. 输入 输入有三行,第一行为 ...

  9. ●BZOJ 3796 Mushroom追妹纸

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

随机推荐

  1. JMeter学习笔记(一) 工具的安装和基本介绍

    因为网上的资料比较多,就不多描述了,在此引用了其他大神的文档,用于学习 这个文档中有比较详细的jmeter工具介绍: https://wenku.baidu.com/view/64f3a5f75901 ...

  2. 《Node.js核心技术教程》读书笔记---思维导图版

    书薄,挺经看!

  3. HDU-1053:Advanced Fruits(LCS+路径保存)

    链接:HDU-1053:Advanced Fruits 题意:将两个字符串合成一个串,不改变原串的相对顺序,可将相同字母合成一个,求合成后最短的字符串. 题解:LCS有三种状态转移方式,将每个点的状态 ...

  4. linux主机上,UnixBench性能测试工具使用

    1,下载  wget http://soft.laozuo.org/scripts/UnixBench5.1.3.tgz [root@VM_0_15_centos test]# [root@VM_0_ ...

  5. Python的sys.argv使用说明

    刚开始使用这个参数的时候,很不明白其含义.网上搜索很多都是贴的官网上面的一则实例,说看懂,就明白.可是,我看不懂.现在在回头看这个参数使用,并不是很麻烦. 举几个小例子就明白了. 创建一个脚本,内容如 ...

  6. 所见即所得:七大无需编程的DIY开发工具

    现如今,各种DIY开发工具不断的出现,使得企业和个人在短短几分钟内就能完成应用的创建和发布,大大节省了在时间和资金上的投入.此外,DIY工具的出现,也帮助广大不具备专业知识和技术的“移动开发粉”创建自 ...

  7. 第八次ScrumMeeting博客

    第八次ScrumMeeting博客 本次会议于11月2日(四)22时整在3公寓725房间召开,持续20分钟. 与会人员:刘畅.辛德泰.窦鑫泽.张安澜.赵奕.方科栋. 1. 每个人的工作(有Issue的 ...

  8. 如何理解IPD+CMMI+Scrum一体化研发管理解决方案之CMMI篇

    如何快速响应市场的变化,如何推出更有竞争力的产品,如何在竞争中脱颖而出,是国内研发企业普遍面临的核心问题,为了解决这些问题,越来越多的企业开始重视创新与研发管理,加强研发过程的规范化,集成产品开发(I ...

  9. Coin Game

    Problem Description After hh has learned how to play Nim game, he begins to try another coin game wh ...

  10. UVALive - 6887 Book Club 有向环的路径覆盖

    题目链接: http://acm.hust.edu.cn/vjudge/problem/129727 D - Book Club Time Limit: 5000MS 题意 给你一个无自环的有向图,问 ...