BZOJ3145 [Feyat cup 1.5]Str 后缀树、启发式合并
考虑两种情况:
1、答案由一个最长公共子串+可能的一个模糊匹配位置组成。这个用SAM求一下最长公共子串,但是需要注意只出现在\(S\)的开头和\(T\)的结尾的子串是不能够通过额外的一个模糊匹配得到更长的子串的,而对于其他的子串来说都可以。
2、答案由模糊位置两遍的子串构成。暴力就是枚举\(S\)和\(T\)中模糊匹配的位置\(i,j\),那么长度就是\(LCS(i-1,j-1)+LCP(i+1,j+1)+1\)。
注意到\(LCS(i,j)\)是对正串建SAM得到的前缀树上\(S[:i]\)和\(T[:j]\)对应的点的LCA的Longest;\(LCP(i,j)\)是对反串建SAM得到的后缀树上的\(S[i:]\)和\(T[j:]\)对应节点的LCA的Longest,所以我们可以把这个问题变为类似于两棵树上LCA深度和最大值的一个问题。
对于这个问题,我们考虑在前缀树上dfs,对于每个节点用set维护其子树内所有的合法前缀在后缀树上的dfs序,每一次加入一个子树的时候用启发式合并,用dfs序相邻的两个点的LCA更新当前点的答案,最后用当前点的Longest加上当前点的答案更新总答案。
#include<bits/stdc++.h>
using namespace std;
const int _ = 4e5 + 7;
struct SAM{
int trs[_][27] , Lst[_] , fa[_] , pos[_] , cnt = 1; bool flg[_];
int extend(int p , int l , int c , bool f = 1){
int t = ++cnt; Lst[t] = pos[t] = l; flg[t] = f;
while(p && !trs[p][c]){trs[p][c] = t; p = fa[p];} if(!p){fa[t] = 1; return t;}
int q = trs[p][c]; if(Lst[q] == Lst[p] + 1){fa[t] = q; return t;}
int k = ++cnt; memcpy(trs[k] , trs[q] , sizeof(trs[q]));
fa[k] = fa[q]; fa[q] = fa[t] = k; Lst[k] = Lst[p] + 1;
while(trs[p][c] == q){trs[p][c] = k; p = fa[p];} return t;
}
vector < int > ch[_]; int dfn[_] , to[_][20] , ts , dep[_];
void dfs(int x){
dfn[x] = ++ts; dep[x] = dep[fa[x]] + 1; to[x][0] = fa[x];
for(int i = 1 ; to[x][i - 1] ; ++i) to[x][i] = to[to[x][i - 1]][i - 1];
for(auto t : ch[x]){dfs(t); flg[x] |= flg[t];}
}
void build(){for(int i = 2 ; i <= cnt ; ++i) ch[fa[i]].push_back(i); dfs(dep[1] = 1);}
int LCA(int p , int q){
if(dep[p] < dep[q]) swap(p , q);
for(int i = 18 ; i >= 0 ; --i) if(dep[p] - (1 << i) >= dep[q]) p = to[p][i];
if(p == q) return Lst[p];
for(int i = 18 ; i >= 0 ; --i) if(to[p][i] != to[q][i]){p = to[p][i]; q = to[q][i];}
return Lst[to[p][0]];
}
}sam[3]; char str[_]; int id[2][_] , mx[_] , LS , LT , L , ans;
struct cmp{bool operator ()(int a , int b){return sam[1].dfn[a] < sam[1].dfn[b];}};
set < int , cmp > n1[_] , n2[_];
void merge(int p , int q){
if(n1[p].size() + n2[p].size() < n1[q].size() + n2[q].size()){n1[p].swap(n1[q]); n2[p].swap(n2[q]);}
for(auto t : n1[q]){
auto it = n2[p].lower_bound(t); if(it != n2[p].end()) mx[p] = max(mx[p] , sam[1].LCA(*it , t));
if(it != n2[p].begin()) mx[p] = max(mx[p] , sam[1].LCA(*--it , t));
}
for(auto t : n2[q]){
auto it = n1[p].lower_bound(t); if(it != n1[p].end()) mx[p] = max(mx[p] , sam[1].LCA(*it , t));
if(it != n1[p].begin()) mx[p] = max(mx[p] , sam[1].LCA(*--it , t));
}
for(auto t : n1[q]) n1[p].insert(t); for(auto t : n2[q]) n2[p].insert(t);
}
void dfs(int x){
if(sam[0].pos[x] && sam[0].pos[x] <= LS - 2) n1[x].insert(id[1][sam[0].pos[x] + 2]);
if(sam[0].pos[x] >= LS + 2 && sam[0].pos[x] <= L - 2) n2[x].insert(id[1][sam[0].pos[x] + 2]);
for(auto t : sam[0].ch[x]){dfs(t); merge(x , t);}
if(mx[x]) ans = max(ans , mx[x] + sam[0].Lst[x] + 1);
}
int main(){
scanf("%s" , str + 1); LS = strlen(str + 1); str[LS + 1] = 'z' + 1;
scanf("%s" , str + LS + 2); LT = strlen(str + LS + 2); L = strlen(str + 1);
id[0][0] = id[1][L + 1] = 1;
for(int i = 1 ; i <= L ; ++i) id[0][i] = sam[0].extend(id[0][i - 1] , i , str[i] - 'a');
for(int i = L ; i ; --i) id[1][i] = sam[1].extend(id[1][i + 1] , L - i + 1 , str[i] - 'a');
int pre = 1; for(int i = 1 ; i <= LS ; ++i) pre = sam[2].extend(pre , i , str[i] - 'a' , i != LS);
int cur = 1 , len = 0; sam[2].build();
for(int i = LS + 2 ; i <= L ; ++i){
while(cur && !sam[2].trs[cur][str[i] - 'a']) len = sam[2].Lst[cur = sam[2].fa[cur]];
if(!cur) cur = 1; else{cur = sam[2].trs[cur][str[i] - 'a']; ++len;}
ans = max(ans , len + !sam[2].flg[cur]);
}
sam[0].build(); sam[1].build(); dfs(1); cout << min(ans , min(LS , LT)); return 0;
}
BZOJ3145 [Feyat cup 1.5]Str 后缀树、启发式合并的更多相关文章
- BZOJ3145 : [Feyat cup 1.5]Str
如果不存在模糊点,那么答案就是两个串的最长公共子串. 如果模糊点是某个串的开头或者结尾,那么可以暴力枚举另一个串中的某个前后缀更新答案. 否则,假设模糊点在第一个串里是$i$,在第二个串里是$j$,那 ...
- [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\)的最长模糊匹配公共子串 模糊匹配 : 至多一 ...
- Bzoj2534:后缀自动机 主席树启发式合并
国际惯例的题面:考虑我们求解出字符串uvu第一个u的右端点为i,第二个u的右端点为j,我们需要满足什么性质?显然j>i+L,因为我们选择的串不能是空串.另外考虑i和j的最长公共前缀(也就是说其p ...
- 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并
题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
- P3302 [SDOI2013]森林(主席树+启发式合并)
P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...
- 【BZOJ-3123】森林 主席树 + 启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2738 Solved: 806[Submit][Status] ...
- [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- 【主席树 启发式合并】bzoj3123: [Sdoi2013]森林
小细节磕磕碰碰浪费了半个多小时的时间 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M ...
随机推荐
- ORACLE监听理解
参考官方文档Net Services Reference的7 Oracle Net Listener Parameters (listener.ora) 1 监听概念 oracle监听,是个服务器端进 ...
- Python学习日记(四十一) Mysql数据库篇 九
前言 索引的主要作用是起到约束和加速查找,ORM框架(sqlalchemy)是用类和对象对数据库进行操作 索引的种类 按种类去分 1.普通索引:能够加速查找 2.主键索引:能够加速查找.不能为空.不能 ...
- 配置以https访问网站
环境 centos7 nginx1.16.1 一.申请证书(已有域名) 进入阿里云控制台,点击域名(我已经弄好了,一开始是没有ssl选项) 点击免费开启ssl 点购买->选择免费版 购买成功后 ...
- 使用docker搭建redis-cluster环境
目录 基础环境信息 搭建步骤 搭建中遇到的问题 其他参考 临时接到一个测试任务,而测试需要用到redis-cluster环境,却没有现成的环境可用,于是只能自力更生搭建测试环境.一开始想采用在 ...
- [转]【会话技术】Session技术
创建时间:6.29 & 6.30 一.Session技术 Session技术是将数据存储在服务器端的技术,会为每个客户端都创建一块内存空间 存储客户的数据,但客户端需要每次都携带一个标识ID ...
- 团队项目-Beta冲刺及发布说明
请大家在每次作业开头添加格式描述: 这个作业属于哪个课程 <课程的链接> 这个作业要求在哪里 <作业要求的链接> 团队名称 <写上团队名称>(附上团队博客链接) 这 ...
- K8S当中的本地卷(Local PV)的使用
Local PV是从kuberntes 1.10开始引入,本质目的是为了解决hostPath的缺陷.通过PV控制器与Scheduler的结合,会对local PV做针对性的逻辑处理,从而,让Pod在多 ...
- 机器取代人类成为现实,Linux shell才可被取代?
机器取代人类成为现实,Linux shell才可被取代? 新睿云 新睿云 新睿云-让云服务触手可及 本次笔者用通俗易懂的语言介绍一下Linux shell,由于笔者能力有限,如有有描述不准确的地方还请 ...
- 【java】ORA-12505, TNS:listener does not currently know of SID given in connect descriptor
如果是负载均衡,则 jdbc.url=jdbc:oracle:thin:@(description=(address_list= (address=(host=XX.XXX.X.XX) (protoc ...
- LeetCode 622. Design Circular Queue
原题链接在这里:https://leetcode.com/problems/design-circular-queue/ 题目: Design your implementation of the c ...