BZOJ3145 : [Feyat cup 1.5]Str
如果不存在模糊点,那么答案就是两个串的最长公共子串。
如果模糊点是某个串的开头或者结尾,那么可以暴力枚举另一个串中的某个前后缀更新答案。
否则,假设模糊点在第一个串里是$i$,在第二个串里是$j$,那么此时对答案的贡献为$lcp(i+1,j+1)+lcs(i-1,j-1)+1$。
将两个串用特殊字符拼接,求出正串的后缀数组以及反串的后缀数组,那么$lcp(i+1,j+1)+lcs(i-1,j-1)+1$等价于两个height数组的区间最小值的和。
考虑从大到小枚举第一个数,每次把所有大于等于它的部分全部合并,那么在另一个数组里显然只有相邻的后缀有用。
所以对于每个集合建立两棵平衡树,维护两个串在反串里的rank。
在启发式合并的时候,只需要在另一个串对应的平衡树里找到前驱后继然后更新答案即可。
时间复杂度$O(n\log^2n)$。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
using namespace std;
const int N=400010,M=200005;
char sa[N],sb[N],s[N];int na,nb,n,i,j,Log[N],ans;
struct DS{
char s[N];
int rk[N],sa[N],height[N],tmp[N],cnt[N],f[18][M];
void suffixarray(int n,int m){
int i,j,k;n++;
for(i=0;i<n*2+5;i++)rk[i]=sa[i]=height[i]=tmp[i]=0;
for(i=0;i<m;i++)cnt[i]=0;
for(i=0;i<n;i++)cnt[rk[i]=s[i]]++;
for(i=1;i<m;i++)cnt[i]+=cnt[i-1];
for(i=0;i<n;i++)sa[--cnt[rk[i]]]=i;
for(k=1;k<=n;k<<=1){
for(i=0;i<n;i++){
j=sa[i]-k;
if(j<0)j+=n;
tmp[cnt[rk[j]]++]=j;
}
sa[tmp[cnt[0]=0]]=j=0;
for(i=1;i<n;i++){
if(rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k])cnt[++j]=i;
sa[tmp[i]]=j;
}
memcpy(rk,sa,n*sizeof(int));
memcpy(sa,tmp,n*sizeof(int));
if(j>=n-1)break;
}
for(j=rk[height[i=k=0]=0];i<n-1;i++,k++)
while(~k&&s[i]!=s[sa[j-1]+k])height[j]=k--,j=rk[sa[j]+1];
}
void build(){
int i,j;
for(i=1;i<=n;i++)f[0][i]=height[i];
for(j=1;j<18;j++)for(i=1;i+(1<<j-1)<=n;i++)f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]);
}
inline int ask(int x,int y){
int k=Log[y-x+1];
return min(f[k][x],f[k][y-(1<<k)+1]);
}
inline int lcp(int x,int y){
if(x>y)swap(x,y);
return ask(x+1,y);
}
}A,B;
int q[M],f[M],ca[M],cb[M],size[M],g[M],v[M<<1],nxt[M<<1],ed,lcp;
set<int>TA[M],TB[M];
inline bool cmp(int x,int y){return A.height[x]>A.height[y];}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x,int y,int z){
f[x]=z;
if(A.sa[x]<na){
int j=A.sa[x]-2;
if(j>=0){
j=B.rk[n-1-j];
TA[z].insert(j);
set<int>::iterator k=TB[z].lower_bound(j);
if(k!=TB[z].end())ans=max(ans,lcp+B.lcp(j,*k));
if(k!=TB[z].begin())k--,ans=max(ans,lcp+B.lcp(j,*k));
}
}
if(A.sa[x]>na){
int j=A.sa[x]-2;
if(j>na){
j=B.rk[n-1-j];
TB[z].insert(j);
set<int>::iterator k=TA[z].lower_bound(j);
if(k!=TA[z].end())ans=max(ans,lcp+B.lcp(j,*k));
if(k!=TA[z].begin())k--,ans=max(ans,lcp+B.lcp(j,*k));
}
}
for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x,z);
}
inline void merge(int x,int y){
x=f[x],y=f[y];
if(size[x]>size[y])swap(x,y);
if(ca[x]&&cb[y]||cb[x]&&ca[y])ans=max(ans,lcp-1);
ca[y]|=ca[x],cb[y]|=cb[x],size[y]+=size[x];
TA[x].clear(),TB[x].clear();
add(x,y),add(y,x);
dfs(x,y,y);
}
int main(){
for(i=2;i<N;i++)Log[i]=Log[i>>1]+1;
scanf("%s%s",sa,sb);
na=strlen(sa);
nb=strlen(sb);
if(na==1||nb==1)return puts("1"),0;
for(i=0;i<na;i++)s[n++]=sa[i];
s[n++]='#';
for(i=0;i<nb;i++)s[n++]=sb[i];
for(i=0;i<n;i++)A.s[i]=B.s[n-i-1]=s[i];
A.suffixarray(n,128);
B.suffixarray(n,128);
B.build();
for(i=1;i<=n;i++){
f[i]=i,size[i]=1;
if(A.sa[i]<na){
ca[i]=1;
j=A.sa[i]-2;
if(j>=0)TA[i].insert(B.rk[n-1-j]);
}
if(A.sa[i]>na){
cb[i]=1;
j=A.sa[i]-2;
if(j>na)TB[i].insert(B.rk[n-1-j]);
}
}
for(i=1;i<n;i++)q[i]=i+1;
sort(q+1,q+n,cmp);
for(i=1;i<n;i++)lcp=A.height[q[i]],merge(q[i]-1,q[i]);
j=A.rk[1];
for(lcp=N,i=j-1;i;i--){
lcp=min(lcp,A.height[i+1]);
if(A.sa[i]>na+1)ans=max(ans,lcp);
}
for(lcp=N,i=j+1;i<=n;i++){
lcp=min(lcp,A.height[i]);
if(A.sa[i]>na+1)ans=max(ans,lcp);
}
j=A.rk[na+2];
for(lcp=N,i=j-1;i;i--){
lcp=min(lcp,A.height[i+1]);
if(A.sa[i]&&A.sa[i]<na)ans=max(ans,lcp);
}
for(lcp=N,i=j+1;i<=n;i++){
lcp=min(lcp,A.height[i]);
if(A.sa[i]&&A.sa[i]<na)ans=max(ans,lcp);
}
j=B.rk[nb+2];
for(lcp=N,i=j-1;i;i--){
lcp=min(lcp,B.height[i+1]);
if(B.sa[i]&&B.sa[i]<nb)ans=max(ans,lcp);
}
for(lcp=N,i=j+1;i<=n;i++){
lcp=min(lcp,B.height[i]);
if(B.sa[i]&&B.sa[i]<nb)ans=max(ans,lcp);
}
j=B.rk[1];
for(lcp=N,i=j-1;i;i--){
lcp=min(lcp,B.height[i+1]);
if(B.sa[i]>nb+1)ans=max(ans,lcp);
}
for(lcp=N,i=j+1;i<=n;i++){
lcp=min(lcp,B.height[i]);
if(B.sa[i]>nb+1)ans=max(ans,lcp);
}
return printf("%d",ans+1),0;
}
BZOJ3145 : [Feyat cup 1.5]Str的更多相关文章
- BZOJ3145 [Feyat cup 1.5]Str 后缀树、启发式合并
传送门--BZOJCH 考虑两种情况: 1.答案由一个最长公共子串+可能的一个模糊匹配位置组成.这个用SAM求一下最长公共子串,但是需要注意只出现在\(S\)的开头和\(T\)的结尾的子串是不能够通过 ...
- [BZOJ 3145][Feyat cup 1.5]Str 解题报告
[Feyat cup 1.5]Str DescriptionArcueid,白姬,真祖的公主.在和推倒贵看电影时突然对一个问题产生了兴趣:我们都知道真祖和死徒是有类似的地方.那么从现代科学的角度如何解 ...
- Bzoj 3145 - [Feyat cup 1.5]Str
bzoj 3145 - [Feyat cup 1.5]Str Description 给你两个长度\(10^5\)级别的串\(S, T\) 求\(S,T\)的最长模糊匹配公共子串 模糊匹配 : 至多一 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- Sam做题记录
Sam做题记录 Hihocoder 后缀自动机二·重复旋律5 求一个串中本质不同的子串数 显然,答案是 \(\sum len[i]-len[fa[i]]\) Hihocoder 后缀自动机三·重复旋律 ...
- Python数据分析实例操作
import pandas as pd #导入pandas import matplotlib.pyplot as plt #导入matplotlib from pylab import * mpl. ...
- eval(PHP 4, PHP 5)
eval — 把字符串作为PHP代码执行 说明 mixed eval ( string $code_str ) 把字符串 code_str 作为PHP代码执行. 除了其他,该函数能够执行储存于数据库文 ...
- PHP 一句话木马
eval 函数 eval() 函数把字符串按照 PHP 代码来计算 该字符串必须是合法的 PHP 代码,且必须以分号结尾 如果没有在代码字符串中调用 return 语句,则返回 NULL.如果代码中存 ...
- Codeforces Round #405 (rated, Div. 2, based on VK Cup 2017 Round 1) 菜鸡只会ABC!
Codeforces Round #405 (rated, Div. 2, based on VK Cup 2017 Round 1) 全场题解 菜鸡只会A+B+C,呈上题解: A. Bear and ...
随机推荐
- 利用 Rational ClearCase ClearMake 构建高性能的企业级构建环境
转载地址:http://www.ibm.com/developerworks/cn/rational/r-cn-clearmakebuild/ 构建管理是 IBM® Rational® ClearCa ...
- JS判断IE版本并在页面显示内容
<script type="text/javascript"> var isIE = function (ver) { var b = document.createE ...
- Android 中的缓存机制与实现
Android开发本质上就是手机和互联网中的web服务器之间进行通信,就必然需要从服务端获取数据,而反复通过网络获取数据是比较耗时的,特别是访问比较多的时候,会极大影响了性能,Android中可通过二 ...
- PAL/NTSC 制电视广播技术有关知识--FPGA
1.PAL和NTSC的区别 常见的电视信号制式是PAL和NTSC,另外还有SECAM等. NTSC即正交平衡调幅制,PAL为逐行倒像正交平衡调幅制. (1)PAL电视标准 PAL电视标准,每秒25帧 ...
- Redis笔记(六)Redis的消息通知
Redis的消息通知可以使用List类型的LPUSH和RPOP(左进右出),当然更方便的是直接使用Redis的Pub/Sub(发布/订阅)模式. >>使用List实现队列 使用列表类型的L ...
- 设计模式学习之备忘录模式(Memento,行为型模式)(19)
假如我们已经记录一个人的个人信息,但是发现信息写错了,然后我先备份下再去修改,结果发现原来的信息是正确的,于是我就看备份的个人信息还原到初始的状态,下面我们用代码去实现 class Program { ...
- Shell编程基础教程6--shell函数
6.shell函数 6.1.定义函数 简介: shell允许将一组命令集或语句形成一个可用块,这些块成为shell函数 定义函数的格式 ...
- 攻城狮在路上(叁)Linux(十七)--- linux磁盘与文件管理概述
一.复习知识点: 1.扇区是最小的物理存储单位,大小为512bytes. 2.扇区组成一个圆,成为柱面,柱面是分区的最小单位. 3.第一个扇区很重要,因为包含了MBR(446字节)和分区表(64字节) ...
- Win10 UAP 标题栏
//自定义标题栏 var view = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView(); ApplicationViewTi ...
- PMP 第一章 引论
1 项目的特点 独特性 临时性 但创造的成果一般和其特点相反. 2 什么是项目管理? 什么是项目? 项目管理就是将知识 技能 工具与技术应用于项目活动,以满足项目的要求,达到项目的目的. 项目管理通过 ...