Description

给定一个串 \(S\),求一个序列 \(a_i\),满足 \(a_i\) 是原串的子串,且 \(a_i\) 在 \(a_{i-1}\) 中至少出现两次,求这个序列的最大的长度

题面

Solution

根据后缀自动机的性质可以做,首先建出 \(parent\) 树,然后满足条件的序列一定是树上的一条链去掉一些节点

然后就是需要满足出现两次的要求了:

因为是祖先关系,所以至少出现了一次,设 \(pos[i]\) 表示节点 \(i\) 所接受的子串都是以原串中 \(pos[i]\) 这个位置结尾的

另外一次我们就找到这个子串在原串中所代表的区间:\([pos[x]-(len[x]-len[fa[x]]),pos[x]]\),如果这个节点在某个儿子节点所代表的区间中出现了两次,那么就符合要求了

我们用线段树维护 \(pos\) 集合就行了,我们从下往上线段树合并就行了

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,ch[N][26],fa[N],cur=1,cnt=1,len[N],b[N],f[N],ans=0;char s[N];
int pos[N],rt[N],ls[N*30],rs[N*30],tt=0,head[N],nxt[N],to[N],num=0;
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline void Modify(int &x,int l,int r,int sa){
if(!x)x=++tt;
if(l==r)return ;
int mid=(l+r)>>1;
if(sa<=mid)Modify(ls[x],l,mid,sa);
else Modify(rs[x],mid+1,r,sa);
}
inline void ins(int c){
int p=cur;cur=++cnt;len[cur]=len[p]+1;
for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur;
if(!p)fa[cur]=1;
else{
int q=ch[p][c];
if(len[p]+1==len[q])fa[cur]=q;
else{
int nt=++cnt;len[nt]=len[p]+1;
memcpy(ch[nt],ch[q],sizeof(ch[nt]));
fa[nt]=fa[q];fa[q]=fa[cur]=nt;
for(;p && ch[p][c]==q;p=fa[p])ch[p][c]=nt;
}
}
}
inline int merge(int x,int y){
if(!x || !y)return x+y;
int c=++tt;
ls[c]=merge(ls[x],ls[y]);
rs[c]=merge(rs[x],rs[y]);
return c;
}
inline void dfs(int x){
for(int i=head[x];i;i=nxt[i]){
dfs(to[i]),rt[x]=merge(rt[x],rt[to[i]]);
if(!pos[x])pos[x]=pos[to[i]];
}
}
inline bool qry(int x,int l,int r,int sa,int se){
if(!x)return false;
if(sa<=l && r<=se)return true;
int mid=(l+r)>>1;
if(se<=mid)return qry(ls[x],l,mid,sa,se);
if(sa>mid)return qry(rs[x],mid+1,r,sa,se);
return qry(ls[x],l,mid,sa,mid)|qry(rs[x],mid+1,r,mid+1,se);
}
inline void dfs1(int x){
for(int i=head[x],t,u;i;i=nxt[i]){
u=to[i];
t=qry(rt[b[x]],1,n,pos[u]-len[u]+len[b[x]],pos[u]-1);
if(t)f[u]=f[x]+1,b[u]=u;
else f[u]=f[x],b[u]=b[x];
dfs1(u);
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;i++)
ins(s[i]-'a'),pos[cur]=i,Modify(rt[cur],1,n,i);
for(int i=2;i<=cnt;i++)link(fa[i],i);
dfs(1);
for(int i=head[1];i;i=nxt[i])b[to[i]]=to[i],f[to[i]]=1,dfs1(to[i]);
for(int i=2;i<=cnt;i++)ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}

Codeforces 700E. Cool Slogans的更多相关文章

  1. Codeforces 700E. Cool Slogans 字符串,SAM,线段树合并,动态规划

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF700E.html 题解 首先建个SAM. 一个结论:对于parent树上任意一个点x,以及它所代表的子树内任 ...

  2. Codeforces.700E.Cool Slogans(后缀自动机 线段树合并 DP)

    题目链接 \(Description\) 给定一个字符串\(s[1]\).一个字符串序列\(s[\ ]\)满足\(s[i]\)至少在\(s[i-1]\)中出现过两次(\(i\geq 2\)).求最大的 ...

  3. [LOJ 6288]猫咪[CF 700E]Cool Slogans

    [LOJ 6288]猫咪[CF 700E]Cool Slogans 题意 给定一个字符串 \(T\), 求一个最大的 \(K\) 使得存在 \(S_1,S_2,\dots,S_k\) 满足 \(S_1 ...

  4. SA / SAM 题目集

    上一次做 SA / SAM 相关的题还要数到某场毒瘤 NOIP 模拟赛--这么久没做了都快忘光了--写点东西记录一些最近做到的水好题. LOJ2059 「TJOI / HEOI2016」字符串 题意 ...

  5. 【CF700E】Cool Slogans(后缀自动机)

    [CF700E]Cool Slogans(后缀自动机) 题面 洛谷 CodeForces 题解 构建后缀自动机,求出后缀树 现在有个比较明显的\(dp\) 设\(f[i]\)表示从上而下到达当前点能够 ...

  6. Codeforces 1063F - String Journey(后缀数组+线段树+dp)

    Codeforces 题面传送门 & 洛谷题面传送门 神仙题,做了我整整 2.5h,写篇题解纪念下逝去的中午 后排膜拜 1 年前就独立切掉此题的 ymx,我在 2021 年的第 5270 个小 ...

  7. python爬虫学习(5) —— 扒一下codeforces题面

    上一次我们拿学校的URP做了个小小的demo.... 其实我们还可以把每个学生的证件照爬下来做成一个证件照校花校草评比 另外也可以写一个物理实验自动选课... 但是出于多种原因,,还是绕开这些敏感话题 ...

  8. 【Codeforces 738D】Sea Battle(贪心)

    http://codeforces.com/contest/738/problem/D Galya is playing one-dimensional Sea Battle on a 1 × n g ...

  9. 【Codeforces 738C】Road to Cinema

    http://codeforces.com/contest/738/problem/C Vasya is currently at a car rental service, and he wants ...

随机推荐

  1. DistBlockNet:A Distributed Blockchains-Based Secure SDN Architecture for IOT Network

    现有问题 随着IOT中智能设备多样性和数目的增加,IOT的灵活性,效率,可用性,安全性和可扩展性的问题越来越明显. 实验目标 按照高适应性,可用性,容错性,性能,可靠性,可扩展性和安全性的设计原则,构 ...

  2. Android webview Mixed Content无法显示图片解决

    转自:http://blog.csdn.net/crazy_zihao/article/details/51557425 前言 在使用WebView加载https资源文件时,如果认证证书不被Andro ...

  3. 关于搭建MyBatis框架(二)

    由于在[关于使用Mybatis的使用说明(一)http://www.cnblogs.com/zdb292034/p/8675766.html]中存在不太完善地方,通过此片文档进行修订: 阅读指南:(1 ...

  4. 剑指offer-数据流中的中位数

    题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值.   ...

  5. __all__

    相信很多人第一次见到这个__all__都很好奇,他有什么作用 那他到底有什么作用呢? 先上代码 from scrapy.utils.reqser import request_to_dict, req ...

  6. C语言学习之弹跳小球

    重新回过头来看了一遍C语言,才发现我自己的无知,C语言其实好强大,我之前学的不过是一点C语法和做几个数学题.正好3月份的考试要考C语言,重新学一遍,先是在中国大学mooc上把翁恺老师的C语言刷了一遍, ...

  7. java程序员最不愿意看到的十件事

     0.遍历结果集并构造对象如果你是个时髦的开发者而不是专业人员,显然你从某篇博客中读过有开发者遇到Hibernate的“性能问题”,因而认为ORM都不好,觉得手动编码“明显更好”.喜欢的话你当然可以用 ...

  8. GIT入门笔记(16)- 分支创建和管理

    查看分支:git branch创建分支:git branch <name>切换分支:git checkout <name>创建+切换分支:git checkout -b < ...

  9. kafka HA

    1. replication 如图.1所示,同一个 partition 可能会有多个 replica(对应 server.properties 配置中的 default.replication.fac ...

  10. logback中配置的日志文件的生成地址

    配置文件如下 <?xml version="1.0" encoding="UTF-8"?> <configuration debug=&quo ...