[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的更多相关文章

  1. NABCD模型(猫咪记单词)

    项目需求分析与建议-NABCD模型(猫咪记单词)   N (Need 需求) 对于现在的学生,尤其是大学生来说,学习英语是一件非常重要的事.我们有四级六级托福雅思等各种各样的英语方面的考试.而学习英语 ...

  2. [TYVJ] P1423 GF和猫咪的玩具

    GF和猫咪的玩具 描述 Description GF同学和猫咪得到了一个特别的玩具,这个玩具由n个金属环(编号为1---n),和m条绳索组成,每条绳索连接两个不同的金属环,并且长度相同.GF左手拿起金 ...

  3. 猫咪记单词Beta版使用说明

    猫咪记单词Beta版使用说明 一.项目背景 英语四级考试.六级考试.托福.雅思等英语方面的考试是现在大学生必须面对的问题.同时因为学生对手机的使用越来越频繁,而且仅仅通过书本背诵单词又比较无聊坚持的时 ...

  4. Cal Cat for Mac(猫咪控日历工具)安装

    1.软件简介    Cal Cat 是 macOS 系统上一款猫咪控日历工具,可以将系统内置的日历工具美化成猫咪风格的日历,超级可爱的猫咪可是猫咪控的最爱了,喜欢的朋友快快用上吧. 加州猫是一个桌面集 ...

  5. 猫咪记单词——NABCD模型分析

    N ——Need 需求:学习英语是一件非常重要的事.面对各种各样的考试,学习英语,最重要的就是词汇量,背单词是提高词汇量的最直接的方法,但是单纯的背单词太单调.寻找一些合适的,更易于接受的背单词学习英 ...

  6. 算法 PK 猫咪 | 章鱼保罗后继竟然是只猫?

    简评:一只名叫阿喀琉斯(Achilles)的白猫一边小声叫着,一边慵懒地在分别插有俄罗斯和沙特阿拉伯国旗的食盆间踱步.这只看起来并不出众的小猫住在俄罗斯圣彼得堡埃尔米塔日博物馆(State Hermi ...

  7. TYVJ1423 GF和猫咪的玩具

    Description: GF同学和猫咪得到了一个特别的玩具,这个玩具由n个金属环(编号为1---n),和m条绳索组成,每条绳索连接两个不同的金属环,并且长度相同.GF左手拿起金属环L,猫咪右手(或者 ...

  8. COGS 1191. [Tyvj Feb11] 猫咪的进化

    ★   输入文件:neko.in   输出文件:neko.out   简单对比时间限制:1 s   内存限制:128 MB [背景] 对于一只猫咪来说,它是有九条命的.但是并不是所有的猫咪都是这样,只 ...

  9. CTF 两道web整数溢出题目(猫咪银行和ltshop)

    ①猫咪银行: (2018中科大hackgame) 一开始给十个CTB,而flag需要20个CTB,我们需要理财赚够20个. 理财是只能买入TDSU才可以获得收益.我们先上来直接把CTB全部换成TDSU ...

随机推荐

  1. mysql--事务详解

    事务的四大特性: # 原子性(atomicity) 一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作 ...

  2. 使用layer.msg 时间设置不起作用

    前几天使用layer.msg设置时间后发现不起作用,这里记录一下. 开始出错误的代码: 后面查看文档后得知调用layer.msg后如果有后续操作需要写在function()中: //eg1 layer ...

  3. linux与ubuntu下vsftp的安装使用

    vsftp工具是linux与类linux系统上常用的ftp传输工具,按百度上的说法,它的不同点与好处有九点,不明觉厉,有兴趣的可以深入验证: 一.它是一个安全.高速.稳定的FTP服务器: 二.它可以做 ...

  4. SQL --- where 1=1 与 1<> 1

    1.Sql 中的查询语句中的where 字句是为了带条件进行查询,那么使用where 1=1  后查询的是什么 首先:查询表   tb_obge  中的所有字段 select * from dbo.o ...

  5. c# Winform 继承窗体 无法拖动修改控件大小

    问题描述: 一个窗体集成父窗体,发现无法直接拖动修改的控件,比如修改大小等 特征: 不禁使父窗体控件,就算新加一个控件也会这样:鼠标放到控件移动手方块上会出现一个“继承的控件”的tooptip, 异常 ...

  6. python基础(3):变量、常量、注释、基本数据类型

    1. 变量 变量:将运算的中间结果暂存到内存,以便后续程序调⽤. 可以直接运算,如下所示: print(3+5+6) print((3+5+6)*12) print(((3+5+6)*12)+3) p ...

  7. MySQL入门——在Linux下安装和卸载MariaDB

    MySQL入门——在Linux下安装和卸载MariaDB 摘要:本文主要学习了如何在Linux系统中安装和卸载MariaDB数据库. 查看有没有安装过MariaDB 使用命令查看有没有安装过: [ro ...

  8. centos 配置sentry+钉钉+邮件通知

    1.sentry官方推荐docker方式安装.使用docker-compose,最好是centos7 2.卸载旧版本 yum remove docker docker-common docker-se ...

  9. django5-书籍与出版社关联外键

    1.外键相关 一对多的概念 ,这里是一个出版社对应本书籍 ! 设计表使用model models.ForeignKey('关联一', on_delete=models.CASCADE) #给多设置外键 ...

  10. 如何给HTML页面设置行高

    设置行高 由于简单还是老样子直接上代码了哦,注意:line-height属性值可以使用固定值如:20px..和百分比如:20%. 如果想让文字垂直居中如下:行高的主要作用是用来设置文本的垂直方向居中对 ...