CF700E Cool Slogans SAM、线段树合并、树形DP
在最优的情况下,序列\(s_1,s_2,...,s_k\)中,\(s_i (i \in [2 , k])\)一定会是\(s_{i-1}\)的一个\(border\),即\(s_i\)同时是\(s_{i-1}\)的前缀和后缀,否则一定可以通过减去\(s_{i-1}\)的一个前缀和后缀使得满足条件。
对原串建立\(SAM\),因为有互为后缀的条件,所以\(s_1,s_2,...,s_k\)会对应\(parent\)树一条链上的若干状态。
发现可以在\(parent\)树上DP。设\(f_i\)表示到达\(i\)状态时序列的最长长度,转移看它祖先中\(f\)最大且长度最短的串是否在当前串中出现了至少\(2\)次。
判断\(A\)是否在\(B\)中出现了至少两次也不是很麻烦。处理出\(A,B\)状态的任意一个\(endpos\),记做\(pos_A,pos_B\),然后用线段树合并得到\(A,B\)状态的\(endpos\)集合,那么\(A\)在\(B\)中出现了至少两次意味着\(A\)的\(endpos\)集合与\([pos_B - len_B + len_A , pos_B]\)的交集的大小\(\geq 2\)。注意到我们需要求的\(AB\)满足\(A\)是\(B\)的一个后缀,所以只需要判断\(A\)的\(endpos\)集合与\([pos_B - len_B + len_A , pos_B)\)是否有交就可以了。
注意:\(SAM\)的一个状态中可能有多个串,但是题目中,因为某个串出现,同一状态的其他串也一定会在同一位置出现,所以这些串是等价的,直接取每个状态的最长串即可。因此,可能会存在选出的\(s_i\)不是\(s_{i-1}\)的\(border\),但并不会影响答案的大小。
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
//This code is written by Itst
using namespace std;
const int MAXN = 4e5 + 7;
namespace segtree{
struct node{
int l , r , sz;
}Tree[MAXN << 5];
int rt[MAXN] , cnt;
#define lch Tree[x].l
#define rch Tree[x].r
#define mid ((l + r) >> 1)
int insert(int t , int l , int r , int tar){
int x = ++cnt;
Tree[x] = Tree[t];
++Tree[x].sz;
if(l == r) return x;
if(mid >= tar) lch = insert(lch , l , mid , tar);
else rch = insert(rch , mid + 1 , r , tar);
return x;
}
int merge(int p , int q){
if(!p || !q) return p + q;
int x = ++cnt;
Tree[x].sz = Tree[q].sz + Tree[p].sz;
lch = merge(Tree[p].l , Tree[q].l);
rch = merge(Tree[p].r , Tree[q].r);
return x;
}
bool query(int x , int l , int r , int L , int R){
if(!Tree[x].sz) return 0;
if(l >= L && r <= R) return 1;
if(mid >= L && query(lch , l , mid , L , R)) return 1;
return mid < R && query(rch , mid + 1 , r , L , R);
}
}
using segtree::rt; using segtree::merge; using segtree::query;
namespace SAM{
int Lst[MAXN] , Sst[MAXN] , fa[MAXN] , trans[MAXN][26] , endpos[MAXN];
int cnt = 1 , lst = 1 , L;
char s[MAXN];
void insert(int len , int x){
int t = ++cnt , p = lst;
endpos[t] = Lst[lst = t] = len;
while(p && !trans[p][x]){
trans[p][x] = t;
p = fa[p];
}
if(!p){Sst[t] = fa[t] = 1; return;}
int q = trans[p][x];
Sst[t] = Lst[p] + 2;
if(Lst[q] == Lst[p] + 1){fa[t] = q; return;}
int k = ++cnt;
memcpy(trans[k] , trans[q] , sizeof(trans[k]));
Lst[k] = Lst[p] + 1; Sst[k] = Sst[q];
Sst[q] = Lst[p] + 2;
fa[k] = fa[q]; fa[q] = fa[t] = k;
while(trans[p][x] == q){
trans[p][x] = k;
p = fa[p];
}
}
void init(){
scanf("%d %s" , &L , s + 1);
for(int i = 1 ; i <= L ; ++i)
insert(i , s[i] - 'a');
}
vector < int > ch[MAXN];
int ans = 0 , top[MAXN] , len[MAXN];
void dfs(int x){
if(endpos[x]) rt[x] = segtree::insert(rt[x] , 1 , L , endpos[x]);
for(auto t : ch[x]){
dfs(t);
if(!endpos[x]) endpos[x] = endpos[t];
rt[x] = merge(rt[x] , rt[t]);
}
}
void dp(int x){
if(fa[x])
if(fa[x] == 1 || query(rt[top[fa[x]]] , 1 , L , endpos[x] - Lst[x] + Lst[top[fa[x]]] , endpos[x] - 1)){
len[x] = len[fa[x]] + 1;
top[x] = x;
ans = max(ans , len[x]);
}
else{
len[x] = len[fa[x]];
top[x] = top[fa[x]];
}
for(auto t : ch[x]) dp(t);
}
void work(){
for(int i = 2 ; i <= cnt ; ++i)
ch[fa[i]].push_back(i);
dfs(1);
dp(1);
cout << ans;
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in" , "r" , stdin);
//freopen("out" , "w" , stdout);
#endif
SAM::init(); SAM::work();
return 0;
}
CF700E Cool Slogans SAM、线段树合并、树形DP的更多相关文章
- CF700E Cool Slogans——SAM+线段树合并
RemoteJudge 又是一道用线段树合并来维护\(endpos\)的题,还有一道见我的博客CF666E 思路 先把\(SAM\)建出来 如果两个相邻的串\(s_i\)和\(s_{i+1}\)要满足 ...
- CF700E:Cool Slogans(SAM,线段树合并)
Description 给你一个字符串,如果一个串包含两个可有交集的相同子串,那么这个串的价值就是子串的价值+1.问你给定字符串的最大价值子串的价值. Input 第一行读入字符串长度$n$,第二行是 ...
- CF700E Cool Slogans 后缀自动机 + right集合线段树合并 + 树形DP
题目描述 给出一个长度为n的字符串s[1],由小写字母组成.定义一个字符串序列s[1....k],满足性质:s[i]在s[i-1] (i>=2)中出现至少两次(位置可重叠),问最大的k是多少,使 ...
- Codeforces 700E. Cool Slogans 字符串,SAM,线段树合并,动态规划
原文链接https://www.cnblogs.com/zhouzhendong/p/CF700E.html 题解 首先建个SAM. 一个结论:对于parent树上任意一个点x,以及它所代表的子树内任 ...
- CF700E-Cool Slogans【SAM,线段树合并,dp】
正题 题目链接:https://www.luogu.com.cn/problem/CF700E 题目大意 给出一个字符串\(S\),求一个最大的\(k\)使得存在\(k\)个字符串其中\(s_1\)是 ...
- CF1037H Security——SAM+线段树合并
又是一道\(SAM\)维护\(endpos\)集合的题,我直接把CF700E的板子粘过来了QwQ 思路 如果我们有\([l,r]\)对应的\(SAM\),只需要在上面贪心就可以了.因为要求的是字典序比 ...
- 【NOI2018】你的名字(SAM & 线段树合并)
Description Hint Solution 不妨先讨论一下无区间限制的做法. 首先"子串"可以理解为"前缀的后缀",因此我们定义一个 \(\lim(i) ...
- 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree
原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...
- UOJ#395. 【NOI2018】你的名字 字符串,SAM,线段树合并
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ395.html 题解 记得同步赛的时候这题我爆0了,最暴力的暴力都没调出来. 首先我们看看 68 分怎么做 ...
- loj#2059. 「TJOI / HEOI2016」字符串 sam+线段树合并+倍增
题意:给你一个子串,m次询问,每次给你abcd,问你子串sa-b的所有子串和子串sc-d的最长公共前缀是多长 题解:首先要求两个子串的最长公共前缀就是把反过来插入变成最长公共后缀,两个节点在paren ...
随机推荐
- 视觉slam领域经典综述和具体应用场景
一.经典综述文章 1. Durrant-Whyte H, Bailey T. Simultaneous localization and mapping: part I[J]. IEEE robot ...
- http请求之get和post的区别
前言:大家现在度娘一下,查得最多的区别,可能就是: “Get把参数写在URL中,Post通过请求体来传参的” “GET没有POST安全,因为Get参数直接显示在URL上” “Get请求在URL中传送的 ...
- Salesforce服务云简介
服务云简介 Salesforce的服务云(Service Cloud)是专注于客服和呼叫中心解决方案的子系统.它是Salesforce核心CRM系统的一部分. 服务云特性 服务云提供了客户服务和呼叫中 ...
- 程序员Web面试之前端框架等知识
基于前面2篇博客: 程序员Web面试之jQuery 程序员Web面试之JSON 您已经可以顺利进入Web开发的大门. 但是要动手干,还需要了解一些已有的前端框架.UI套件,即要站在巨人肩膀上而不是从轮 ...
- CentOS7的/tmp目录自动清理规则
CentOS6以下系统(含)使用watchtmp + cron来实现定时清理临时文件的效果,这点在CentOS7发生了变化. 在CentOS7下,系统使用systemd管理易变与临时文件,与之相关的系 ...
- 从零自学Java-9.描述对象
1.为类或对象创建变量:2.使用对象和类的方法:3.调用方法并返回一个值:4.创建构造函数:5.给方法传递参数:6.使用this来引用对象:7.创建新对象. 程序VirusLab:测试Virus类的功 ...
- React Refs
React Refs React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上. 这个特殊的属性允许你引用 render() 返回的相应的支撑实例( back ...
- 洗礼灵魂,修炼python(48)--巩固篇—模块
模块 其实前面都说过的,不过还是系统的再说一次,相信学到这,大部分都被搞忘了吧,所以再提一下,也为后面的博文做铺垫 1.什么是模块 在程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越 ...
- docker端口映射启动报错Error response from daemon: driver failed programming external connectivity on endpoint jms_guacamole
问题描述:今天跳板机的一个guacamole用docker重新启动报错了 [root@localhost opt]# docker start d82e9c342a Error response / ...
- 4.4Python数据类型(4)之字符串函数
返回总目录 目录: 1.字符串的查找计算 2.字符串的转换 3.字符串的填充压缩 4.字符串的分割拼接 5.字符串的判定 (一)字符串的查找计算 (1)len(str)计算字符串的总数 (2)find ...