[LOJ 6288]猫咪[CF 700E]Cool Slogans
[LOJ 6288]猫咪[CF 700E]Cool Slogans
题意
给定一个字符串 \(T\), 求一个最大的 \(K\) 使得存在 \(S_1,S_2,\dots,S_k\) 满足 \(S_1\) 是 \(T\) 的子串且 \(\forall 1\le i< k\) 有 \(S_{i+1}\) 是 \(S\) 的双子串.
其中双子串的定义是: 若 \(a\) 在 \(b\) 的至少两个不同位置作为子串出现则 \(a\) 为 \(b\) 的双子串. 出现位置可以重叠.
\(|T|\le 2\times 10^5\).
题解
考试的时候被沙雕题目描述搞得迷迷糊糊的结果没发现是原题←菜的真实
显然对于每个子串我们可以这个子串里挑一个答案最大且的双子串作为这个子串的答案.
我们发现当我们挑出一个子串 \(S_1\) 后, 可以通过对左右端点进行适当缩减来刚好卡到"每一个双子串都是上一个串的一个border"的程度. 因为如果出现了不是border的情况, 可以把前面所有的 \(S_i\) 全都缩短, 不难发现这样并不会导致答案变劣.
那么实际上要计算的就是每个子串最多迭代几个border. 考虑在SAM上DP. SAM的结点上只能控制右端点, 左端点是一个区间, 不难发现只要搞右端点相同就可以了. 线段树合并搞出每个点的 right 集合, 判断一下答案最大的祖先是否能对当前点做出贡献就可以了. 能做出贡献就 \(+1\), 否则就不加.
至于判断, 因为当前 right 集合对应的长度最大为 len 的子串都是完全一样的, 所以随便取一个位置判断就可以了.
参考代码
#include <bits/stdc++.h>
const int MAXN=4e5+10;
struct Node{
int l;
int r;
int cnt;
Node* lch;
Node* rch;
Node(int,int);
void Insert(int);
int Query(int,int);
};
Node* N[MAXN];
int n;
int cnt=1;
int root=1;
int last=1;
int s[MAXN];
int prt[MAXN];
int len[MAXN];
int val[MAXN];
int pos[MAXN];
int tprt[MAXN];
char str[MAXN];
std::map<char,int> chd[MAXN];
int Extend(char);
Node* Merge(Node*,Node*);
int main(){
scanf("%s",str+1);
n=strlen(str+1);
for(int i=1;i<=n;i++){
int x=Extend(str[i]);
N[x]->Insert(pos[x]=i);
}
for(int i=1;i<=cnt;i++)
s[i]=i;
std::stable_sort(s+1,s+cnt+1,[](int a,int b){return len[a]>len[b];});
for(int i=1;i<cnt;i++){
N[prt[s[i]]]=Merge(N[prt[s[i]]],N[s[i]]);
pos[prt[s[i]]]=pos[s[i]];
}
int ans=0;
for(int i=cnt-1;i>=1;i--){
int p=s[i];
if(prt[p]==root){
val[p]=1;
tprt[p]=p;
}
else{
assert(N[p]->Query(pos[p],pos[p]));
int last=tprt[prt[p]];
int cnt=N[last]->Query(pos[p]-len[p]+(len[prt[last]]+1),pos[p]);
if(cnt>=2){
val[p]=val[last]+1;
tprt[p]=p;
}
else{
val[p]=val[last];
tprt[p]=last;
}
}
ans=std::max(ans,val[p]);
}
printf("%d\n",ans);
return 0;
}
void Node::Insert(int x){
++this->cnt;
if(this->l!=this->r){
int mid=(this->l+this->r)>>1;
if(x<=mid){
if(this->lch==NULL)
this->lch=new Node(this->l,mid);
this->lch->Insert(x);
}
else{
if(this->rch==NULL)
this->rch=new Node(mid+1,this->r);
this->rch->Insert(x);
}
}
}
int Extend(char x){
int p=last;
int np=++cnt;
N[last=np]=new Node(1,n);
len[np]=len[p]+1;
while(p&&!chd[p].count(x))
chd[p][x]=np,p=prt[p];
if(!p)
prt[np]=root;
else{
int q=chd[p][x];
if(len[q]==len[p]+1)
prt[np]=q;
else{
int nq=++cnt;
N[nq]=new Node(1,n);
len[nq]=len[p]+1;
chd[nq]=chd[q];
prt[nq]=prt[q];
prt[q]=nq;
prt[np]=nq;
while(p&&chd[p][x]==q)
chd[p][x]=nq,p=prt[p];
}
}
return np;
}
Node* Merge(Node* a,Node* b){
if(a==NULL)
return b;
if(b==NULL)
return a;
Node* cur=new Node(a->l,b->r);
cur->cnt=a->cnt+b->cnt;
cur->lch=Merge(a->lch,b->lch);
cur->rch=Merge(a->rch,b->rch);
return cur;
}
int Node::Query(int l,int r){
if(l<=this->l&&this->r<=r)
return this->cnt;
else{
int ans=0;
if(this->lch&&l<=this->lch->r)
ans+=this->lch->Query(l,r);
if(this->rch&&this->rch->l<=r)
ans+=this->rch->Query(l,r);
return ans;
}
}
Node::Node(int l,int r):l(l),r(r),cnt(0),lch(NULL),rch(NULL){}
[LOJ 6288]猫咪[CF 700E]Cool Slogans的更多相关文章
- NABCD模型(猫咪记单词)
项目需求分析与建议-NABCD模型(猫咪记单词) N (Need 需求) 对于现在的学生,尤其是大学生来说,学习英语是一件非常重要的事.我们有四级六级托福雅思等各种各样的英语方面的考试.而学习英语 ...
- [TYVJ] P1423 GF和猫咪的玩具
GF和猫咪的玩具 描述 Description GF同学和猫咪得到了一个特别的玩具,这个玩具由n个金属环(编号为1---n),和m条绳索组成,每条绳索连接两个不同的金属环,并且长度相同.GF左手拿起金 ...
- 猫咪记单词Beta版使用说明
猫咪记单词Beta版使用说明 一.项目背景 英语四级考试.六级考试.托福.雅思等英语方面的考试是现在大学生必须面对的问题.同时因为学生对手机的使用越来越频繁,而且仅仅通过书本背诵单词又比较无聊坚持的时 ...
- Cal Cat for Mac(猫咪控日历工具)安装
1.软件简介 Cal Cat 是 macOS 系统上一款猫咪控日历工具,可以将系统内置的日历工具美化成猫咪风格的日历,超级可爱的猫咪可是猫咪控的最爱了,喜欢的朋友快快用上吧. 加州猫是一个桌面集 ...
- 猫咪记单词——NABCD模型分析
N ——Need 需求:学习英语是一件非常重要的事.面对各种各样的考试,学习英语,最重要的就是词汇量,背单词是提高词汇量的最直接的方法,但是单纯的背单词太单调.寻找一些合适的,更易于接受的背单词学习英 ...
- 算法 PK 猫咪 | 章鱼保罗后继竟然是只猫?
简评:一只名叫阿喀琉斯(Achilles)的白猫一边小声叫着,一边慵懒地在分别插有俄罗斯和沙特阿拉伯国旗的食盆间踱步.这只看起来并不出众的小猫住在俄罗斯圣彼得堡埃尔米塔日博物馆(State Hermi ...
- TYVJ1423 GF和猫咪的玩具
Description: GF同学和猫咪得到了一个特别的玩具,这个玩具由n个金属环(编号为1---n),和m条绳索组成,每条绳索连接两个不同的金属环,并且长度相同.GF左手拿起金属环L,猫咪右手(或者 ...
- COGS 1191. [Tyvj Feb11] 猫咪的进化
★ 输入文件:neko.in 输出文件:neko.out 简单对比时间限制:1 s 内存限制:128 MB [背景] 对于一只猫咪来说,它是有九条命的.但是并不是所有的猫咪都是这样,只 ...
- CTF 两道web整数溢出题目(猫咪银行和ltshop)
①猫咪银行: (2018中科大hackgame) 一开始给十个CTB,而flag需要20个CTB,我们需要理财赚够20个. 理财是只能买入TDSU才可以获得收益.我们先上来直接把CTB全部换成TDSU ...
随机推荐
- #3144. 「APIO 2019」奇怪装置
#3144. 「APIO 2019」奇怪装置 题目描述 考古学家发现古代文明留下了一种奇怪的装置.该装置包含两个屏幕,分别显示两个整数 \(x\) 和 \(y\). 经过研究,科学家对该装置得出了一个 ...
- 重载&重写的区别
重载(Overload) 1.重载(Overload)是让类以统一的方式处理不同类型数据的一种手段.多个同名函数同时存在,具有不同的参数个数/类型. 2.重载(Overload)是一个类中多态性的一种 ...
- d03
回顾: 两个环境 工具环境:Jmeter的下载.启动.基本使用 项目环境:学生信息管理系统 两种接口: 天气预报:4个接口----GET方法 学生信息管理系统: 被测软件的学院信息接口: 4类: 查询 ...
- Spring Session工作原理
本文首发于 vivo互联网技术 微信公众号 https://mp.weixin.qq.com/s/KCOFv0nRuymkX79-RZi9eg 作者:张正林 目录:1.引入背景2.使用方法3.工作流程 ...
- javascript解决在safari浏览器中使用history.back()返回上一页后页面不会刷新的问题
我们知道,在JavaScript中提供了一个window.history.back()方法用于返回上一页,另外也可以使用window.history.go(-1)返回上一页(跳转). 在其他的主流浏览 ...
- C++ 运行时类别识别
运行时动态类型的识别其实应该是多态方面的知识,这里我直接拿来单独成章. dynamic_cast和static_cast 1.static_cast用法如下: static_cast < Typ ...
- jquery 图片缩放插件使用
https://cdn.bootcss.com/d3-transition/1.1.1/d3-transition.js http://www.jq22.com/jquery-info9291
- C# - WinFrm应用程序MessageBox自动关闭小实验
概述 在程序中MessageBox弹出的对话框,用于向用户展示消息,这是一个模式窗口,可阻止应用程序中的其他操作,直到用户将其关闭.但是有时候在自动化程序中,如果弹出对话框,程序将会中断,等待人工的干 ...
- Web前端基础(6):CSS(三)
1. 定位 定位有三种:相对定位.绝对定位.固定定位 1.1 相对定位 现象和使用: 1.如果对当前元素仅仅设置了相对定位,那么与标准流的盒子什么区别. 2.设置相对定位之后,我们才可以使用四个方向的 ...
- 对Python中函数参数类型及排序问题,三个方面的总结
Python中函数的参数问题有点复杂,主要是因为参数类型问题导致的情况比较多,下面来分析一下. 参数类型:缺省参数,关键字参数,不定长位置参数,不定长关键字参数. 其实总共可以分为 位置参数和关键字参 ...