BZOJ3796 : Mushroom追妹纸
将S1与S2用#号拼接在一起形成S串
将S3与S串跑KMP求出S3在S串中每次出现的位置l[i]
对于S串每个后缀i,求出f[i]表示该串不包含S3串的最长前缀
然后求出S串的后缀数组
先从小到大扫描后缀数组,
同时维护一个tmp表示S2中的串与现在的串的最长公共前缀,且没有出现S3,
如果碰到一个S1的后缀,那么更新ans=max(ans,min(f[sa[i]],tmp))
如果碰到一个S2的后缀,那么更新tmp=max(tmp,f[sa[i]])
然后将tmp与height取一个最小值
最后再从后往前扫描一次即可
时间复杂度$O(n)$
#include<cstdio>
#include<cstring>
using std::strlen;
inline bool leq(int a1,int a2,int b1,int b2){return a1<b1||a1==b1&&a2<=b2;}
inline bool leq(int a1,int a2,int a3,int b1,int b2,int b3){return a1<b1||a1==b1&&leq(a2,a3,b2,b3);}
inline void radixPass(int*a,int*b,int*r,int n,int K){
int*c=new int[K+1];
int i,sum,t;
for(i=0;i<=K;i++)c[i]=0;
for(i=0;i<n;i++)c[r[a[i]]]++;
for(i=sum=0;i<=K;i++)t=c[i],c[i]=sum,sum+=t;
for(i=0;i<n;i++)b[c[r[a[i]]]++]=a[i];
delete[]c;
}
void suffixArray(int*T,int*SA,int n,int K){
int n0=(n+2)/3,n1=(n+1)/3,n2=n/3,n02=n0+n2;
int*R=new int[n02+3];R[n02]=R[n02+1]=R[n02+2]=0;
int*SA12=new int[n02+3];SA12[n02]=SA12[n02+1]=SA12[n02+2]=0;
int*R0=new int[n0];
int*SA0=new int[n0];
int i,j,name=0,c0=-1,c1=-1,c2=-1,p=0,t=n0-n1,k=0;
for(i=j=0;i<n+n0-n1;i++)if(i%3)R[j++]=i;
radixPass(R,SA12,T+2,n02,K),radixPass(SA12,R,T+1,n02,K),radixPass(R,SA12,T,n02,K);
for(i=0;i<n02;i++){
if(T[SA12[i]]!=c0||T[SA12[i]+1]!=c1||T[SA12[i]+2]!=c2)name++,c0=T[SA12[i]],c1=T[SA12[i]+1],c2=T[SA12[i]+2];
if(SA12[i]%3==1)R[SA12[i]/3]=name;else R[SA12[i]/3+n0]=name;
}
if(name<n02)for(suffixArray(R,SA12,n02,name),i=0;i<n02;i++)R[SA12[i]]=i+1;else for(i=0;i<n02;i++)SA12[R[i]-1]=i;
for(i=j=0;i<n02;i++)if(SA12[i]<n0)R0[j++]=3*SA12[i];
for(radixPass(R0,SA0,T,n0,K);k<n;k++){
#define GetI() (SA12[t]<n0?SA12[t]*3+1:(SA12[t]-n0)*3+2)
i=GetI(),j=SA0[p];
if(SA12[t]<n0?leq(T[i],R[SA12[t]+n0],T[j],R[j/3]):leq(T[i],T[i+1],R[SA12[t]-n0+1],T[j],T[j+1],R[j/3+n0])){
SA[k]=i;
if(++t==n02)for(k++;p<n0;p++,k++)SA[k]=SA0[p];
}else{
SA[k]=j;
if(++p==n0)for(k++;t<n02;t++,k++)SA[k]=GetI();
}
}
delete[]R;delete[]SA12;delete[]SA0;delete[]R0;
}
#define N 100010
char s1[N],s2[N],s3[N],s[N],ch;
int l1,l2,l3,n,nxt[N],S[N],SA[N],rank[N],height[N],f[N],i,j,k,cnt,loc[N],ans,tmp;
inline int min(int a,int b){return a<b?a:b;}
inline void Min(int&a,int b){if(a>b)a=b;}
inline void Max(int&a,int b){if(a<b)a=b;}
int main(){
scanf("%s%s%s",s1,s2,s3);
l1=strlen(s1),l2=strlen(s2),l3=strlen(s3);
for(i=0;i<l1;i++)s[i]=s1[i];
for(s[n=l1]='#',i=0;i<l2;i++)s[++n]=s2[i];++n;
for(nxt[0]=j=-1,i=1;i<l3;nxt[i++]=j){
while(~j&&s3[j+1]!=s3[i])j=nxt[j];
if(s3[j+1]==s3[i])j++;
}
for(j=-1,i=0;i<n;i++){
while(~j&&s3[j+1]!=s[i])j=nxt[j];
if(s3[j+1]==s[i])j++;
if(j==l3-1)loc[++cnt]=i-l3+1,j=nxt[j];
}
for(i=0,j=1;i<n;i++){
while(j<=cnt&&loc[j]<i)j++;
if(j>cnt)f[i]=n-i;else f[i]=loc[j]+l3-i-1;
}
for(i=0;i<=l1;i++)Min(f[i],l1-i);
for(i=0;i<n;i++)if(s[i]=='#')S[i]=27;else S[i]=s[i]-'a'+1;
suffixArray(S,SA,n,27);
for(i=0;i<n;i++)rank[SA[i]]=i;
for(k=i=0;i<n;i++)if(rank[i]==n-1)k=0;
else{
if(k)k--;
for(j=SA[rank[i]+1];S[i+k]==S[j+k];k++);
height[rank[i]]=k;
}
for(i=tmp=0;i<n;i++){
if(SA[i]<l1)Max(ans,min(tmp,f[SA[i]]));
if(SA[i]>l1)Max(tmp,f[SA[i]]);
Min(tmp,height[i]);
}
for(i=n-1,tmp=0;~i;i--){
if(SA[i]<l1)Max(ans,min(tmp,f[SA[i]]));
if(SA[i]>l1)Max(tmp,f[SA[i]]);
if(i)Min(tmp,height[i-1]);
}
return printf("%d",ans),0;
}
BZOJ3796 : Mushroom追妹纸的更多相关文章
- BZOJ3796 Mushroom追妹纸 字符串 SA KMP
原文链接https://www.cnblogs.com/zhouzhendong/p/9253173.html 题目传送门 - BZOJ3796 题意 找一个串 $w$ 满足: 1.$w$ 是 $s_ ...
- BZOJ3796 Mushroom追妹纸(二分答案+后缀数组+KMP)
求出一个串使得这个串是\(s1,s2\)的子串.串中不包含\(s3\). 如果没有这个\(s3\)就可以二分答案,然后height小于二分值分一组.看看每组里是不是出现过\(s1,s2\)的后缀.判断 ...
- [BZOJ3796]Mushroom追妹纸:后缀自动机+KMP
分析 这道题有个\(O(n)\)的后缀自动机做法,感觉很好理解就在这说一下. 先对\(s1\)和\(s2\)求最长公共子串,对于\(s2\)的每一个下标\(i\),求一个\(f[i]\)表示以\(s2 ...
- 【BZOJ3796】Mushroom追妹纸 二分+hash
[BZOJ3796]Mushroom追妹纸 Description Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决 ...
- [BZOJ 3796]Mushroom追妹纸
[BZOJ 3796]Mushroom追妹纸 题目 Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他 ...
- 【bzoj3796】Mushroom追妹纸 hash/sa+kmp+二分
Description Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意--写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他从网上找到了两篇极佳的情书, ...
- 【bzoj3796】Mushroom追妹纸
Portal -->bzoj3796 Description 给出字符串s1.s2.s3,找出一个字符串w,满足: 1.w是s1的子串: 2.w是s2的子串: 3.s3不是w的子串. 求w的 ...
- 【bzoj3796】Mushroom追妹纸 Kmp+二分+Hash
题目描述 给出字符串s1.s2.s3,找出一个字符串w,满足: 1.w是s1的子串: 2.w是s2的子串: 3.s3不是w的子串. 4.w的长度应尽可能大 求w的最大长度. 输入 输入有三行,第一行为 ...
- ●BZOJ 3796 Mushroom追妹纸
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3796 题解: 题意: 给出三个串 A,B,C 找出一个最长串 S, 使得 ...
随机推荐
- java常见异常集锦
1. java.lang.nullpointerexception 这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用了未经初始化的对象或者是不存在的对 ...
- intellij idea 如何更改编辑器文本字体和大小
换上了intellij idea之后,第一件事就是想要改变下文字字体,因为在我这个27寸的2k分辨率的屏幕上,文字显然太小了. intellij idea字体设值分成两部分,一部分是UI部分字体字号设 ...
- 【OpenStack】OpenStack系列15之OpenStack高可用详解
高可用 概念 级别 陈本 如何实现 分类 Openstack的HA 虚拟机的HA 虚拟机HA 比较 应用级别HA,Heat的HA模板 组件的HA 示意图 Mysql的HA 三种方式之一——主从同步 ...
- 《ASP.NET1200例》<ItemTemplate>标签在html里面有什么具体的作用
严格的来说 <ItemTemplate> 在html中无意义,他只是针对诸如 Repeater.DataList.GridView中的一个模板 至于里面的含义,你可以这样想,既然Repea ...
- poj 1664
http://poj.org/problem?id=1664 题目是中文的,一个递归的题目 把每一次的苹果分为两类 Ⅰ:所以盘子都放一个,然后其他的在随便放: Ⅱ:有一个盘子没有放苹果: 这样下去的话 ...
- poj 2421 Constructing Roads 解题报告
题目链接:http://poj.org/problem?id=2421 实际上又是考最小生成树的内容,也是用到kruskal算法.但稍稍有点不同的是,给出一些已连接的边,要在这些边存在的情况下,拓展出 ...
- Extjs的数据读取器store和后台返回类型简单解析
工作中用到了Extjs,从后台获取数据的时候,用到了extjs自己的Ext.data.store方法,然后封装了ExtGridReturn方法, 目的:前台用到Ext.data.store读取从后台传 ...
- oracle 序列 详解
序列: 是oacle提供的用于产生一系列唯一数字的数据库对象. l 自动提供唯一的数值 l 共享对象 l 主要用于提供主键值 l 将序列值装入内存可以提高访问效率 创建序列: 1. 要有创建 ...
- p364习题1
- 安装win7或win8系统时UEFI和Legacy模式的设置
很多新型号的笔记本或台式机主板都开始支持UEFI模式,比起原来的Legacy启动减少了BIOS自检,加快平台启动,如下图所示Legacy,UEFI启动过程: 安装系统,建议选择Legacy模式,在UE ...