首先说一下,对一个刚学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的更多相关文章

  1. 5.4 省选模拟赛 修改 线段树优化dp 线段树上二分

    LINK:修改 题面就不放了 大致说一下做法.不愧是dls出的题 以前没见过这种类型的 不过还是自己dp的时候写丑了. 从这道题中得到一个结论 dp方程要写的优美一点 不过写的过丑 优化都优化不了. ...

  2. codehunter 「Adera 6」杯省选模拟赛 网络升级 【树形dp】

    直接抄ppt好了--来自lyd 注意只用对根判断是否哟留下儿子 #include<iostream> #include<cstdio> using namespace std; ...

  3. 【BZOJ-2286】消耗战 虚树 + 树形DP

    2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2120  Solved: 752[Submit][Status] ...

  4. 51nod 1353 树 | 树形DP经典题!

    51nod 1353 树 | 树形DP好题! 题面 切断一棵树的任意条边,这棵树会变成一棵森林. 现要求森林中每棵树的节点个数不小于k,求有多少种切法. 数据范围:\(n \le 2000\). 题解 ...

  5. 【BZOJ-3572】世界树 虚树 + 树形DP

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1084  Solved: 611[Submit][Status ...

  6. bzoj 2286(虚树+树形dp) 虚树模板

    树链求并又不会写,学了一发虚树,再也不虚啦~ 2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5002  Sol ...

  7. 洛谷 P1453 城市环路 ( 基环树树形dp )

    题目链接 题目背景 一座城市,往往会被人们划分为几个区域,例如住宅区.商业区.工业区等等.B市就被分为了以下的两个区域--城市中心和城市郊区.在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市 ...

  8. BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca

    BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的 ...

  9. [10.12模拟赛] 老大 (二分/树的直径/树形dp)

    [10.12模拟赛] 老大 题目描述 因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的特色,办公室群被设计成了树形(n 个点 n − 1 条边的无向连通图), ...

随机推荐

  1. Codeforces 1042C (贪心+模拟)

    题面 传送门 分析 思路简单,但代码较复杂的贪心 分类讨论: 有0 负数有奇数个:将绝对值最小(实际最大)的负数和0全部乘到一起,最后删掉0 负数有偶数个:将0全部乘到一起,最后删掉0 没有0 负数有 ...

  2. Mock接口数据 = mock服务 + iptable配置

    一.mock接口数据应用场景: 1.测试接口A,A接口代码中调用其他服务的B接口,由于开发排期.测试环境不通等原因,依赖接口不可用 2.测试异常情况,依赖接口B返回的数据格式不对.返回None.超时等 ...

  3. Asp.net中GridView使用详解(很全,很经典)

    http://blog.csdn.net/hello_world_wusu/article/details/4052844 Asp.net中GridView使用详解 效果图参考:http://hi.b ...

  4. js中的回调地狱 Callback to Hell

        本文重点:解决方式:1.promise  2. 拆解 function:将各步拆解为单个的 function  3. 通过 Generator 函数暂停执行的效果方式 4. 通过ES8的异步函 ...

  5. 实现 unity MonoBehaviour API5.4 的消息

      顺序(第一次执行.忽略循环) 方法 说明 Editor 1 void Reset() 重置为默认值 ------------------------------------------------ ...

  6. Linux性能优化从入门到实战:04 CPU篇:CPU使用率

      CPU使用率是单位时间内CPU使用情况的统计,以百分比方式展示. $ top top - 11:46:45 up 7 days, 11:52, 1 user, load average: 0.00 ...

  7. Linux架构之Nginx Web基础1

    第41章 Nginx Web基础入门 41.1 Nginx部署 41.1.1 Nginx的安装方式   源码编译 官方仓库 epel仓库 优点 规范 安装简单 安装简单   便于管理 配置易读   缺 ...

  8. php object

    一.访问控制 <?php class Computer{ public $cpu = 880; private $name = 'xiaomi'; public function getname ...

  9. tpcc-mysql测试mysql5.6 (EXT4文件系统)

    操作系统版本:CentOS release 6.5 (Final)  2.6.32-431.el6.x86_64 #1 内存:32G CPU:Intel(R) Xeon(R) CPU E5-2450 ...

  10. JAVA四种引用方式

    JAVA四种引用方式: java.lang.ref: 强引用(直接变量赋值) 软引用(SoftReference): 只有在要发生OOM错误之前才会回收掉老的软引用对象,应用场景主要防止内存溢出.(缓 ...