E. Cool Slogans

链接

题意:

  给定一个字符串S,从中选出k个子串a[1],a[2]...a[k],满足a[i]在a[i+1]中出现了两次(可以重叠),求最大的k。

分析:

  建出SAM,在parent树上dp,dp[i]表示到第i个点,最多选了多少个子串,那么如果fa[i]在i中出现了两次,就可以+1后转移,否则直接继承fa[i]的值即可。

  那么如何判断一个串是否在另一个串中出现了两次?

  后缀自动机上每个点表示多个串,如果点A对应的串在点B对应的串中出现了两次,那么设B的结尾节点是$R_1, R_2...R_k$,那么从这些结尾位置任选一个,设为pos,满足$pos-len[B]+len[A] \sim pos$,A的right集合中,至少满足有两个right在这个区间中。

  --------------------------------------------------------------------------------------------

  这个dp这的好妙妙妙啊。

  那么首先从dp的过程说起。这个dp感觉不太像dp,倒像是模拟。

  我们从一个点A出发,设这个点的对应的最长的串是aba,然后向下走。这个点一定至少包含两个儿子结点。假设它有两个儿子节点,分别是x,y。

  我们首先向x走,存在这一条边就说明了A的right集合和x的不同,且A包含x。然后我们判断x对应的子串是否有两个A,如果有,那让f[x]=f[A]+1即可。没有的话,我们记录下A这个位置(top),然后继续往下走,判断走到的每个点对应的子串是否有两个A,而不是有两个fa[i]。

  因为A在这里分叉了,并且有x,y两个儿子,说明A(aba)在整个串中出现的位置至少有两次,前面的字符不同,假设是这样....caba.....daba.....那么往下走的过程是在当前的串上向前延伸的过程,一定会延伸到两个aba都包含了,然后转移。(这里x,y中只有一个会延伸到两个同时包含)。

  还有一个疑问,就是为什么在计算A在B中是否出现了两次的时候,用的是A这个点,所对应的最长的串,是不是让这个串缩短一下,然后就出现两次了?那么我们考虑ba是否比aba优:如果A存在一个父节点是ba的话,那么我们肯定是用到了ba,如果不存在,说明ba和aba出现的Right集合是一样的,那么aba和ba是一样的。

  

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
int fa[N], ch[N][], len[N], xl[N], pos[N], tmp[N], f[N], top[N];
int ls[N * ], rs[N * ], Root[N];
int tot, Index = , Last = , n;
char s[N]; void update(int l,int r,int &rt,int p) {
if (!rt) rt = ++tot;
if (l == r) return ;
int mid = (l + r) >> ;
if (p <= mid) update(l, mid, ls[rt], p);
else update(mid + , r, rs[rt], p);
}
int Merge(int x,int y) {
if (!x || !y) return x + y;
int z = ++tot; // ÕâÀï±ØÐëҪн¨Ò»¸öµã£¬ÒòΪÒÔÇ°µÄµã»¹ÓÐÓÃ
ls[z] = Merge(ls[x], ls[y]);
rs[z] = Merge(rs[x], rs[y]);
return z;
}
int query(int l,int r,int rt,int L,int R) {
if (!rt) return ;
if (L <= l && r <= R) return ;
int mid = (l + r) >> ;
if (L <= mid && query(l, mid, ls[rt], L, R)) return ;
if (R > mid && query(mid + , r, rs[rt], L, R)) return ;
return ;
}
void extend(int c,int i) {
int NP = ++Index, P = Last; pos[NP] = i;
len[NP] = len[P] + ;
for (; P && !ch[P][c]; P = fa[P]) ch[P][c] = NP;
if (!P) fa[NP] = ;
else {
int Q = ch[P][c];
if (len[Q] == len[P] + ) fa[NP] = Q;
else {
int NQ = ++Index;
len[NQ] = len[P] + ;
pos[NQ] = pos[Q]; // !!!
memcpy(ch[NQ], ch[Q], sizeof ch[Q]);
fa[NQ] = fa[Q];
fa[NP] = fa[Q] = NQ;
for (; P && ch[P][c] == Q; P = fa[P]) ch[P][c] = NQ;
}
}
Last = NP;
update(, n, Root[NP], i);
}
int main() {
freopen("a.in", "r", stdin);
n = read();
scanf("%s", s + );
for (int i = ; i <= n; ++i) extend(s[i] - 'a', i);
for (int i = ; i <= Index; ++i) tmp[len[i]] ++;
for (int i = ; i <= n; ++i) tmp[i] += tmp[i - ];
for (int i = Index; i >= ; --i) xl[tmp[len[i]]--] = i;
for (int i = Index; i > ; --i) {
int x = xl[i];
Root[fa[x]] = Merge(Root[fa[x]], Root[x]);
}
int ans = ;
for (int i = ; i <= Index; ++i) {
int x = xl[i], y = fa[x];
if (y == ) { f[x] = , top[x] = x; continue; }
int z = query(, n, Root[top[y]], pos[x] - len[x] + len[top[y]], pos[x] - );
if (z) f[x] = f[y] + , top[x] = x;
else f[x] = f[y], top[x] = top[y];
ans = max(ans, f[x]);
}
cout << ans;
return ;
}

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

  1. cf 700 B Connecting Universities

    题意:现在给以一棵$n$个结点的树,并给你$2k$个结点,现在要求你把这些节点互相配对,使得互相配对的节点之间的距离(路径上经过边的数目)之和最大.数据范围$1 \leq n \leq 200000, ...

  2. cf 700 A As Fast As Possible

    题意:有$n$个小学生需要到距离为$l$的地方去,步行的速度是$v_1$,它们租了一辆大巴,速度是$v_2$,大巴上最多容纳$k$个乘客,每个小学生最多乘车一次,初始时大巴和小学生都在起点,问至少需要 ...

  3. 做题记录 To 2019.2.13

    2019-01-18 4543: [POI2014]Hotel加强版:长链剖分+树形dp. 3653: 谈笑风生:dfs序+主席树. POJ 3678 Katu Puzzle:2-sat问题,给n个变 ...

  4. HTK计算mfcc/filter_bank源码解析

    HTK计算mfcc/filter_bank源码解析 HTK可以用简单的 HCopy -C config -s scp 求取mfcc或者filter_bank 关于mfcc的原理在 http://my. ...

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

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

  6. ORA-00494: enqueue [CF] held for too long (more than 900 seconds) by 'inst 1, osid 5166'

    凌晨收到同事电话,反馈应用程序访问Oracle数据库时报错,当时现场现象确认: 1. 应用程序访问不了数据库,使用SQL Developer测试发现访问不了数据库.报ORA-12570 TNS:pac ...

  7. 1Z0-053 争议题目解析700

    1Z0-053 争议题目解析700 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 700.Which two statements are true about a duplica ...

  8. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  9. cf Round 613

    A.Peter and Snow Blower(计算几何) 给定一个点和一个多边形,求出这个多边形绕这个点旋转一圈后形成的面积.保证这个点不在多边形内. 画个图能明白 这个图形是一个圆环,那么就是这个 ...

随机推荐

  1. webkit、cef、nwjs、electron、 miniblink浏览器内核优缺点

    市面上作为嵌入的组件的可用的浏览器内核,不外乎这几个:webkit.cef.nwjs.electron. 1.cef:优点是由于集成的chromium内核,所以对H5支持的很全,同时因为使用的人也多, ...

  2. 转:oracle 事务

    原文地址:http://blog.csdn.net/junmail/article/details/5556561 关于Oracle事务的总结 1.什么是事务,事务的特性是什么? 事务的任务便是使数据 ...

  3. [C++] 用Xcode来写C++程序[5] 函数的重载与模板

    用Xcode来写C++程序[5] 函数的重载与模板 此节包括函数重载,隐式函数重载,函数模板,带参数函数模板 函数的重载 #include <iostream> using namespa ...

  4. golang 防知乎 中文验证码 源码

    原创,转载请注明出处! 最开始用图形来模仿文字进行各种角度的倒立和排列,后来切换为文字后,有很多问题.总结如下: 1.程序在画图形和画文字方面不一样,图形的是从原点开始(0,0),而文字则从文字的基线 ...

  5. 重置 Winsock:初始化计算机网络环境

    初始化网络环境,以解决由于软件冲突.病毒原因造成的参数错误问题(复杂网络环境下慎用).批处理代码: netsh winhttp reset proxy netsh winhttp reset trac ...

  6. Spring MVC Hello World 404

    下面的例子说明了如何使用 Spring MVC 框架来编写一个简单的基于 web 的 Hello World 应用程序.下面让我们使用 Eclipse IDE,然后按照下面的步骤使用 Spring 的 ...

  7. SQL——快速定位相关的外键表

  8. MyISAM和innoDB对比,覆盖索引简单回顾

    MyISAM Myisam是Mysql的默认存储引擎,当create创建新表时,未指定新表的存储引擎时,默认使用Myisam. 它不支持事务,也不支持外键,尤其是访问速度快,对事务完整性没有要求或者以 ...

  9. python的unittest框架中如何删除测试数据,清理环境,可以通过addCleanup函数

    def addCleanup(self, function, *args, **kwargs): """Add a function, with arguments, t ...

  10. B/S网络概述

    B/S网络架构 随着Web2.0时代的到来,互联网的网络架构已经从传统的C/S架构转变到更加方便快捷的B/S架构.这样的转化简化了人们上网的方式,也加速了互联网行业的发展. B/S架构的好处: 1.客 ...