bzoj 3796 Mushroom追妹纸——后缀数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3796
长度一般都是 1e5 ,看这个是 5e4 ,一看就是把两个串接起来做。
自己本来想的是把 s3 分别接到 s1 和 s2 后面,做后缀数组求出 s1 和 s2 的每个位置有没有作为开头出现了 s3 ;然后把 s1 和 s2 接起来做后缀数组,二分一个长度作为答案,按 sa[ ] 的顺序遍历每个位置,遇到 s2 的就记录一下它能不能让之后的 s1 和某个 s2 的 LCP >= ans_len ,遇到 s1 就看有没有 s2 和它的 LCP >= ans_len (O(1)),有的话再看看 s1 对应的那个位置后面 ans_len 区域内有没有完整地出现 s3 (可以给每个位置记录 lst[ ] 表示最近的下一个 s3 开头出现的位置),如果没有的话,这个 ans_len 可行;还要倒着做一遍统计后面的 s2 对前面的 s1 的影响。
看了一下题解。原来不用二分答案,因为可以取尽量大的更新答案;而且对于一个 s1 ,最好的 s2 一定是离它最近的 s2 ,因为 LCP 越远越短了;找到一个 LCP 之后,就算后面对应区域内出现了完整的 s3 也不用认为这个 LCP 不合法,可以让 LCP 和不含 s3 部分的长度取 min 来更新答案。
而且算 s1 和 s2 的每个位置有没有作为开头出现 s3 也可以不用后缀数组,做 kmp 即可。
正着和倒着做也可以等价为正着同时统计 s2 对 s1 的影响和 s1 对 s2 的影响。大概是记录 mn1 和 mn2 分别表示 s1 能给出多少贡献和 s2 能给出多少贡献,那么遇到一个 s1 的位置,可以让 mn1 = INF , mn2 = min( mn2 , ht[ i ] ) ;因为 i 位置能否贡献是看从 i+1 开始的 ht[ ] 取 min 的。
注意数组大小。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5e4+,M=1e5+,M2=1e4+,K=;
int sa[M],rk[M],tp[M],tx[M],ht[M],lst[M],nxt[M+M2];
char s[M+M2],s1[N],s2[N],s3[N];
int Mn(int a,int b){return a<b?a:b;}
int Mx(int a,int b){return a>b?a:b;}
void kmp(int m3,int m1,int m2)
{
int n=m1+m2+m3+;
for(int i=;i<=n;i++)
{
int cr=nxt[i-];
while(cr&&s[cr+]!=s[i])cr=nxt[cr];
if(s[cr+]==s[i])nxt[i]=cr+;
if(nxt[i]==m3)
lst[i-m3--m3+]=;
}
lst[m1+m2+]=m1+m2+;
for(int i=m1+m2+;i;i--)
lst[i]=(lst[i]?i:lst[i+]);
}
void Rsort(int n,int nm)
{
for(int i=;i<=nm;i++)tx[i]=;
for(int i=;i<=n;i++)tx[rk[i]]++;
for(int i=;i<=nm;i++)tx[i]+=tx[i-];
for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
}
void get_sa(int n)
{
int nm=;
for(int i=;i<=n;i++)tp[i]=i,rk[i]=s[i]-'a'+;
Rsort(n,nm);
for(int k=;k<=n;k<<=)
{
int tot=;
for(int i=n-k+;i<=n;i++)tp[++tot]=i;
for(int i=;i<=n;i++)
if(sa[i]>k)tp[++tot]=sa[i]-k;
Rsort(n,nm);memcpy(tp,rk,sizeof rk);
nm=;rk[sa[]]=;
for(int i=,u,v;i<=n;i++)
{
u=sa[i]+k;v=sa[i-]+k;if(u>n)u=;if(v>n)v=;
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[u]==tp[v])?nm:++nm;
}
if(nm==n)break;
}
}
void get_ht(int n)
{
for(int i=,k=,j;i<=n;i++)
{
for(k?k--:,j=sa[rk[i]-];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
ht[rk[i]]=k;//rk[i]!!
}
}
void calc(int ps,int len,int &ans,int m3)
{
int ret=Mn(len,lst[ps]-ps+m3-);
ans=Mx(ans,ret);
}
int main()
{
scanf("%s",s1+);scanf("%s",s2+);scanf("%s",s3+);
int m1=strlen(s1+),m2=strlen(s2+),m3=strlen(s3+),n=m1+m2+;
memcpy(s,s3,sizeof s3);s[m3+]=',';
for(int i=m3+,j=;j<=m1;j++,i++)s[i]=s1[j];
s[m3++m1+]='!';//don't be the same with s[m3+1]
for(int i=m3++m1++,j=;j<=m2;j++,i++)s[i]=s2[j];
kmp(m3,m1,m2);
memcpy(s,s1,sizeof s1);s[m1+]='z'+;
for(int i=m1+,j=;j<=m2;j++,i++)s[i]=s2[j];
get_sa(n);get_ht(n); int ans=;
for(int i=,mn1=,mn2=;i<=n;i++)
{
if(sa[i]<=m1)
{
mn1=n; mn2=Mn(mn2,ht[i]);
calc(sa[i],mn2,ans,m3);
}
else if(sa[i]>m1+)
{
mn2=n; mn1=Mn(mn1,ht[i]);
calc(sa[i],mn1,ans,m3);
}
}
printf("%d\n",ans);
return ;
}
bzoj 3796 Mushroom追妹纸——后缀数组的更多相关文章
- bzoj 3796 Mushroom追妹纸 —— 后缀数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3796 先把三个串拼在一起,KMP 求 s1 , s2 中每个位置和 s3 的匹配情况: 注意 ...
- [BZOJ 3796]Mushroom追妹纸
[BZOJ 3796]Mushroom追妹纸 题目 Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他 ...
- bzoj 3796: Mushroom追妹纸【二分+后缀数组+st表】
把三个串加上ASCII大于z的分隔符连起来,然后求SA 显然每个相同子串都是一个后缀的前缀,所以枚举s1的每个后缀的最长和s2相同的前缀串(直接在排序后的数组里挨个找,最近的两个分别属于s1和s2的后 ...
- bzoj 3796: Mushroom追妹纸 AC自动机+后缀自动机+dp
题目大意: 给定三个字符串s1,s2,s3,求一个字符串w满足: w是s1的子串 w是s2的子串 s3不是w的子串 w的长度应尽可能大 题解: 首先我们可以用AC自动机找出s3在s1,s2中出现的位置 ...
- ●BZOJ 3796 Mushroom追妹纸
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3796 题解: 题意: 给出三个串 A,B,C 找出一个最长串 S, 使得 ...
- BZOJ 3796 Mushroom追妹纸 哈希+二分(+KMP)
先把两个串能匹配模式串的位置找出来,然后标记为$1$(标记在开头或末尾都行),然后对标记数组求一个前缀和,这样可以快速查到区间内是否有完整的一个模式串. 然后二分子串(答案)的长度,每次把长度为$md ...
- 【BZOJ3796】Mushroom追妹纸 二分+hash
[BZOJ3796]Mushroom追妹纸 Description Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决 ...
- 【bzoj3796】Mushroom追妹纸 hash/sa+kmp+二分
Description Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意--写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他从网上找到了两篇极佳的情书, ...
- BZOJ3796 : Mushroom追妹纸
将S1与S2用#号拼接在一起形成S串 将S3与S串跑KMP求出S3在S串中每次出现的位置l[i] 对于S串每个后缀i,求出f[i]表示该串不包含S3串的最长前缀 然后求出S串的后缀数组 先从小到大扫描 ...
随机推荐
- Boostnote:适合程序员的笔记软件【转】
本文转载自:https://blog.csdn.net/u013553529/article/details/70306899 Boostnote:适合程序员的笔记软件 注意: Boostnote正在 ...
- 网易编程题——Fibonacci数列
题目描述 Fibonacci数列是这样定义的: F[0] = 0 F[1] = 1 for each i ≥ 2: F[i] = F[i-1] + F[i-2] 因此,Fibonacci数列就形如:0 ...
- eclipse格式化代码快捷键失效解决的一个基本方法
eclipse格式化代码的快捷键Ctrl+Shift+F,是比较常用的一个快捷键之一. 但是用到时却发现按了也没有反应,百度了说是跟搜狗输入法的快捷键冲突了. 搜狗输入法的快捷键Ctrl+Shift+ ...
- thinkPHP中怎么使用阿里云的sdk
使用阿里云官方给的方法总会报错 Class 'Home\Controller\DefaultProfile' not found 这样是因为namespace的原因,将aliyun sdk 放在con ...
- SQL中比较好的For xml 用法实例
--包裹单号 入库时间 交易号 商品分类 商品名称 实付款SELECT a.DeliveryCode AS '包裹单号',a.DomesticWarehouseInTime AS '入库时间',a.T ...
- js进阶---12-11、jquery如何给动态创建出来的元素绑定事件
js进阶---12-11.jquery如何给动态创建出来的元素绑定事件 一.总结 一句话总结:通过事件委托的方式,通过on方法 1.on方法在事件绑定的时候,data方式带额外参数时,字符串参数和其它 ...
- mysql 如果数据不存在,则插入新数据,否则更新 的实现方法
CREATE TABLE `table_test` ( `id` int(11) NOT NULL AUTO_INCREMENT, `my_key` int(11) NOT NULL DEFAULT ...
- SimpleDateFormat函数语法
SimpleDateFormat函数语法: G 年代标志符 y 年 M 月 d 日 h 时 在上午或下午 (1~12) ...
- 数据库oracle(PGA+SGA分配机制)
一.名词解释 (1)SGA:System Global Area是Oracle Instance的基本组成部分,在实例启动时分配;系统全局域SGA主要由三部分构成:共享池.数据缓冲区.日志缓冲区. ( ...
- ARM汇编指令集3
常用ARM指令1:数据处理指令 •数据传输指令 mov mvn mov r1, r0 @两个寄存器之间数据传递 mov r1, #0xff ...