校内模拟赛 : Rima —— 字典树+树形DP
首先说一下,对一个刚学Trie树的蒟蒻来说(就是我),这道题是一道好题。Trie树比较简单,所以就不详细写了。
Rima
内存限制:256 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
上传者: cqbzgm
题目描述
Adrian对单词押韵很感兴趣。如果两个单词的最长公共后缀的长度与两个单词中较长那个的长度一样,或者等于较长单词的长度减一,则这两个单词押韵。换句话说,如果A,B的最长公共后缀LCS(A,B)≥max(|A|,|B|)-1,则A和B押韵。有一天,在阅读一套短篇小说时,他决定创造出能够使每两个相邻单词押韵的最长的单词序列,序列中的每个单词只能出现一次。但是Adrian已经厌倦了这个任务,所以他决定回去读小说,并要求你代替他解决这个任务。
输入格式
第一行输入包含整数N(1≤N≤5*1e5)。表示单词的个数。接下来N行每行包含一个只由小写英文字母组成的字符串。表示可以用于组成序列的单词。数据保证每个单词都是不同的,保证所有单词的长度之和不超过3*1e6。
输出格式
输出一个整数。表示单词序列的最长长度。样例
样例输入1
4
honi
toni
oni
ovi
样例输出1
3
样例输入2
5
ask
psk
krafna
sk
k
样例输出2
4
样例输入3
5
pas
kompas
stas
s
nemarime
样例输出3
1
数据范围与提示
对于30%的数据,N≤18。
首先这道题要用到的是最长公共后缀,所以可以倒着将字符串插入字典树中以方便操作。那么我们便将样例1插入字典树中:
我们可以发现,在Tri树中,具有“押韵”关系的两个点,它们的"end"节点必定是父子或者是兄弟关系,没有例外。(比如oni和honi的end节点就是父子关系,honi和toni就是兄弟关系。)
答案已经很明显了。现在要考虑的是方法。
在考场中,我用的方法是从树的叶节点开始搜索,统计出连通的end节点的数量(这里连通的定义是具有父子关系或兄弟关系)。这样做没有问题,也很好想,但它是错的。如果我们直接暴力统计的,我们会忽略一些特殊情况(虽然这样可以骗至少40分)
这组数据:
7
ab
aab
ccb
cb
bbb
bb
b
如果使用刚才我说的直接统计每个节点在它的子树中end节点的数量(这个节点不一定是end节点,因为这样还包括两个end节点是兄弟的情况),那么它就会输出7,而正确答案却是6。
造成答案错误的原因是我们忽略了题目中的一个限制条件。在这个队列中,只有“相邻”的两个单词押韵才符合答案。
在1节点中,我们直接统计了红点的个数7个。但我们无论如何都无法将"ab","aab","ccb","cb","bbb","bb","b"这7个单词排在一起。原因是因为“b”旁边只能排有2个单词
我们可以按"aab" "ab" "b" "bb" "bbb"的顺序排列我们可以在"ab"和"b"之间插入一个"cb",这样就变成了"aab" "ab" "cb" "b" "bb" "bbb"。但"ccb"却怎么也插不进去了。
让我们回到Tri树中。使用\(f_{u}\)数组来表示一个单词它后面(注意是后面,这意味着这个单词只能接一边。而不能将其它单词接到它的前面。)的最多能接上单词的数量。
关于它的状态转移方程 :
\(f_{u}=max(f_{v}) +sum\) (\(sum\)表示u的子节点中除了f值最大的一个v节点外其它合法子节点的数量(合法意味着这个节点是end节点))
但f数组却不是最终的答案。注意我们对它的定义是在它的后面,也就是只能接上一边,所以状态转移方程不是\(f_{u}=max1(f_{v1}) +max2(f_{v2})+sum\)
(\(max1\) 和\(max2\)是第一大和第二大)
在每个节点中,定义\(ans=max1(f_{v1}) +max2(f_{v2})+sum\),答案就是最大的\(ans\).
(你们直接看代码吧,我自己也解释不清)
#include <iostream>
#include <string>
#include <cstdio>
#include <map>
#include <cstring>
using namespace std;
#define N 500010
#define M 3000010
#define LL long long
string A;
int n,p[M][30],k=1,ans,f[M];
bool IsEnd[M];
void Insert(string A) {
int now=1;
for(int i=A.length()-1;i>=0;i--) {
if(!p[now][A[i]-'a'])
p[now][A[i]-'a']=++k;
now=p[now][A[i]-'a'];
}
IsEnd[now]=1;
}
void dfs(int x) {
int sum=0;
pair<int,int> maxx;
maxx=make_pair(0,0);
for(int i=0,v;i<26;i++)
if(p[x][i]) {
v=p[x][i];
if(IsEnd[v]) sum++;
dfs(v);
maxx=max(maxx,make_pair(maxx.first,f[v]));//这里不用pair也行,但我用其他方法
maxx=max(maxx,make_pair(f[v],maxx.first));//就WA了,所以吹爆pair
f[x]=max(f[x],f[v]);
}
if(IsEnd[x]) f[x]+=max(1,sum);
else f[x]=0;
ans=max(ans,IsEnd[x]+maxx.first+maxx.second+max(0,sum-2));
}
int main() {
cin>>n;
for(int i=1;i<=n;i++) {
cin>>A;
Insert(A);
}
dfs(1);
cout<<ans;
}
校内模拟赛 : Rima —— 字典树+树形DP的更多相关文章
- 5.4 省选模拟赛 修改 线段树优化dp 线段树上二分
LINK:修改 题面就不放了 大致说一下做法.不愧是dls出的题 以前没见过这种类型的 不过还是自己dp的时候写丑了. 从这道题中得到一个结论 dp方程要写的优美一点 不过写的过丑 优化都优化不了. ...
- codehunter 「Adera 6」杯省选模拟赛 网络升级 【树形dp】
直接抄ppt好了--来自lyd 注意只用对根判断是否哟留下儿子 #include<iostream> #include<cstdio> using namespace std; ...
- 【BZOJ-2286】消耗战 虚树 + 树形DP
2286: [Sdoi2011消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2120 Solved: 752[Submit][Status] ...
- 51nod 1353 树 | 树形DP经典题!
51nod 1353 树 | 树形DP好题! 题面 切断一棵树的任意条边,这棵树会变成一棵森林. 现要求森林中每棵树的节点个数不小于k,求有多少种切法. 数据范围:\(n \le 2000\). 题解 ...
- 【BZOJ-3572】世界树 虚树 + 树形DP
3572: [Hnoi2014]世界树 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1084 Solved: 611[Submit][Status ...
- bzoj 2286(虚树+树形dp) 虚树模板
树链求并又不会写,学了一发虚树,再也不虚啦~ 2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5002 Sol ...
- 洛谷 P1453 城市环路 ( 基环树树形dp )
题目链接 题目背景 一座城市,往往会被人们划分为几个区域,例如住宅区.商业区.工业区等等.B市就被分为了以下的两个区域--城市中心和城市郊区.在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市 ...
- BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca
BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的 ...
- [10.12模拟赛] 老大 (二分/树的直径/树形dp)
[10.12模拟赛] 老大 题目描述 因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的特色,办公室群被设计成了树形(n 个点 n − 1 条边的无向连通图), ...
随机推荐
- POJ 1905 题解(二分+几何)
题面 传送门 分析 如图:已知AB=L,弧AB=L(1+nC)" role="presentation" style="position: relative;& ...
- d3与echarts的区别
1. 目前各大公司的大数据平台多使用d3还是echarts?什么时候适合用echarts,什么时候适合用d3? 在我看几种数据可视化平台多使用折线图,面积图和柱状图,条图居多,对于echarts和d3 ...
- 一些关于C#发送邮件的代码
1.命名空间 using System.Net.Mail; 2.创建一个MailMessage类的对象 MailMessage mail = new MailMessage(); MailMessag ...
- ReentrantReadWriteLock实现原理
在java并发包java.util.concurrent中,除了重入锁ReentrantLock外,读写锁ReentrantReadWriteLock也很常用.在实际开发场景中,在使用共享资源时,可能 ...
- C# Windows Services 启动和结束其它进程
将exe所在的绝对路径和进程名配置到配置文件中 <add key="FilePath" value="D:\ABC\ABCD.Console.exe"/& ...
- linux--基础知识3
#linux虚拟终端切换 ctrl+alt+F(1-6) 总共支持六个终端切换 #mkdir /root/boot/目录 在指定路径下新建目录 #touch /目录/文件名 在指定目录创建文件 ...
- react依赖注入之mapStateToProps&&mapDispatchToProps
今天看前辈写的代码,看到mapStateToProps&&mapDispatchToProps处,不明白,于是又是各种找资料,在CSDN博客中发现一篇好文,摘抄到此,方便自己阅读! 原 ...
- [python 学习] argparse模块
https://docs.python.org/3/library/argparse.html#module-argparse
- html 头部设置
https://juejin.im/post/5a4ae29b6fb9a04504083cac <head> <meta charset="UTF-8"> ...
- 进入cmd的另外的一种方式
按Shift键+鼠标右键 进入powershell ,进入的界面和普通的shell界面不一样