[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. vscode源码分析【九】窗口里的主要元素

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...

  2. Linux 编译工具 gcc/g++、Make/Makefile、CMake/CMakeLists.txt、qmake

    前言 编译器的主要工作流程: 源码(Source Code)>> 预处理器(Preprocessor)>> 编译器(Compiler)>> 汇编程序(Assembl ...

  3. Python连载48-正则表达式(中)

    一.正则的写法: . (点好) :表示任意一个字符,除了\n,比如查找所有的一个字符\. [] :匹配中括号中列举的任意字符,比如[L,Y,0], LLY, Y0, LIU \d :任意一个数字 \D ...

  4. Python - 部分PEP8规范

    写代码就像写字一样,为什么有的人写的字十分漂亮,而有的人写的字过后连自己都不认识,最主要还是从一开始是否对自己严格要求.从现在开始就当自己是个初学者,把代码写漂亮点.以下截取了部分PEP8代码规范,里 ...

  5. HikariCP监控指标介绍和应用

    概述 HikariCP提供了一些监控指标,他的监控指标都是基于MicroMeter提供出来的,然后支持Prometheus和Dropwizard.本次我们将讨论一下HikariCp的监控指标有哪些,为 ...

  6. java高并发系列 - 第9天:用户线程和守护线程

    守护线程是一种特殊的线程,在后台默默地完成一些系统性的服务,比如垃圾回收线程.JIT线程都是守护线程.与之对应的是用户线程,用户线程可以理解为是系统的工作线程,它会完成这个程序需要完成的业务操作.如果 ...

  7. Tomcat8史上最全优化实践

    Tomcat8史上最全优化实践 1.Tomcat8优化 1.1.Tomcat配置优化 1.1.1.部署安装tomcat8 1.1.2 禁用AJP连接 1.1.3.执行器(线程池) 1.1.4 3种运行 ...

  8. Android框架Volley使用:Get请求实现

    首先我们在项目中导入这个框架: implementation 'com.mcxiaoke.volley:library:1.0.19' 在AndroidManifest文件当中添加网络权限: < ...

  9. Python之Beautiful Soup 4使用实例

    Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库,它能够通过你喜欢的转换器实现惯用的文档导航.查找.修改文档的方式.Beautiful Soup 4 官方文档: ...

  10. [b0042] python 归纳 (二七)_gui_tkinter_基本使用

    # -*- coding: utf-8 -*- """ 学习 Tkinter画图基本控件使用 逻辑: 放几个 输入控件.点击按钮,将输入控件内容打印出来 使用: 1. 创 ...