题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4567

题解: 显然答案一定小于\(n\times n\), 字符串倒过来变成前缀建Trie, 题意转化如下:

每次可以在一棵树上标记一个点,要求标记一个点之前所有祖先都标记过,标记一个点的价值等于它父亲被标记的时间,最大化价值和(也可以是求所有父子标记时间之差的和的最小值)

一看到这个脑子里立刻蹦出一个贪心: 按照儿子个数从小到大选(用堆维护)

然而是错的

hack数据:

10
aaa
baa
caa
daa
eaa
aa
a
b
ab
bb

正确的方案是按子树大小从小到大选。这里提供一个不知道对不对的证明(其实是拼凑网上的其他题解):

(1) 最优答案一定是DFS序。这个按照父子时间差之和来理解,挺显然。(抱歉我水平有限也就能说到这个份上了……)

(2) DFS序中的最优答案一定是按子树大小从小到大选。感性理解是: 由于是DFS序我们可以只考虑根对答案产生的贡献,最小化根与其所有儿子的时间差之和。然后就相当于有一堆数给他们排序使得前缀和的和最小,然后就显然了……

教训: 贪心这种东西千万不能想当然,一定要证明!要证明!要证明!

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define llong long long
using namespace std;const int N = 1e5;
const int L = 5e5+1e4;
const int S = 26;
struct Edge
{int v,nxt;
} e[(N<<1)+3];
int son[L+3][S+1];
char str[L+3];
bool isky[L+3];
int sz[N+3];
int sonn[N+3];
int fe[N+3];
int fa[N+3];
struct Element
{int u;Element() {}Element(int _u) {u = _u;}bool operator <(const Element &arg) const{return sz[u]>sz[arg.u];}
};
priority_queue<Element> que;
int n,siz,nn,en;void insertstr(char str[],int len)
{int u = 1;for(int i=1; i<=len; i++){if(!son[u][str[i]]) {siz++; son[u][str[i]] = siz;}u = son[u][str[i]];}isky[u] = true;
}void addedge(int u,int v)
{printf("addedge %d %d\n",u,v);en++; e[en].v = v;e[en].nxt = fe[u]; fe[u] = en;
}void dfs0(int u,int anc)
{if(isky[u]) {nn++; addedge(nn,anc); addedge(anc,nn); sonn[anc]++; anc = nn;}for(int i=1; i<=S; i++){int v = son[u][i];if(v){dfs0(v,anc);}}
}void dfs(int u)
{sz[u] = 1;for(int i=fe[u]; i; i=e[i].nxt){if(e[i].v==fa[u]) continue;fa[e[i].v] = u;dfs(e[i].v);sz[u] += sz[e[i].v];}
}int main()
{siz = 1;scanf("%d",&n);for(int i=1; i<=n; i++){scanf("%s",str+1); int len = strlen(str+1);for(int j=1; j<=len; j++) str[j] -= 96;for(int j=1; j<=len+1-j; j++) swap(str[j],str[len+1-j]);insertstr(str,len);}nn = 1; dfs0(1,1);dfs(1);que.push(Element(1));llong ans = 0ll;for(int i=1; i<=nn; i++){int u = que.top().u; que.pop();printf("%d\n",u);ans += sonn[u]*(i-1ll);for(int j=fe[u]; j; j=e[j].nxt){if(e[j].v==fa[u]) continue;fa[e[j].v] = u;que.push(e[j].v);}}ans = n*(n+1ll)/2ll-ans;printf("%lld\n",ans);return 0;
}

BZOJ 4567 [SCOI2016]背单词 (Trie树、贪心)相关推荐

  1. [Scoi2016]背单词[字典树+dfs重构树[类似虚树]]

    解题思路:很明显第一个条件是可以避免的,第二个条件是第三个条件的特殊情况,所以有用的只有第三个条件,现在我们就是想将这些单词重排使得每个单词后缀都在这个单词的前面并且代价最小 我们举个例子: 6 a ...

  2. 【bzoj4567】[Scoi2016]背单词 贪心+trie树

    我个傻逼,这么水的题还调了那么久. 把所有的串都反过来,建trie树,很明显,不同子树间是不影响的. 一定是先选择父亲节点再选子节点,同一个节点先选子树大小最小的儿子即可. 一开始想错了,以为可以直接 ...

  3. 洛谷P2412 查单词 [trie树 RMQ]

    题目背景 滚粗了的HansBug在收拾旧英语书,然而他发现了什么奇妙的东西. 题目描述 udp2.T3如果遇到相同的字符串,输出后面的 蒟蒻HansBug在一本英语书里面找到了一个单词表,包含N个单词 ...

  4. 51nod 1526 分配笔名(Trie树+贪心)

    建出Trie树然后求出一个点子树中有多少笔名和真名.然后贪心匹配即可. #include<iostream> #include<cstring> #include<cst ...

  5. BZOJ4567 SCOI2016背单词(trie+贪心)

    倒过来变成查询前缀.考虑怎么排序.第一条代价n*n就相当于inf,说明一个单词的所有前缀都要排在它前面.那么串的依赖关系就是trie的结构.二三条说明代价是Σidi-idfa,那么显然最后的编号应该是 ...

  6. [BZOJ 4571][Scoi2016]美味(主席树)

    Description 一家餐厅有 n 道菜,编号 1...n ,大家对第 i 道菜的评价值为 ai(1≤i≤n).有 m 位顾客,第 i 位顾客的期 望值为 bi,而他的偏好值为 xi .因此,第 ...

  7. BZOJ 3261 最大异或和 可持久化Trie树

    题目大意:给定一个序列,提供下列操作: 1.在数组结尾插入一个数 2.给定l,r,x,求一个l<=p<=r,使x^a[p]^a[p+1]^...^a[n]最大 首先我们能够维护前缀和 然后 ...

  8. 【图解算法】Trie树

    欢迎来到我的算法专栏,今天我们来讲一种常见的数据结构:Trie树. 我们会对Trie树的性质,相关操作,应用进行讲解,并模拟实现一个简版的Trie树. 目录 1. Trie树 简介 2. Trie树的 ...

  9. BZOJ 1590.Secret Message 秘密信息(Trie树) [Usaco2008 Dec]【BZOJ计划】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 BZOJ简单题合集x Weblink https://hydro.ac/d/bzoj/p/1590 P ...

最新文章

  1. Go modules基础精进,六大核心概念全解析(上)
  2. 训练和验证准确性_通过沉浸式虚拟现实观察动作增强运动想象训练
  3. Alluxio 1.5集群搭建
  4. 数据库连接python_python连接数据库
  5. 路飞学院python官网-路飞学院-Python爬虫实战密训班-第1章
  6. Linux shell 编程(七):流程控制语句
  7. CompletableFuture详解~CompletionStage
  8. C++|STL学习笔记-map的基本操作(插入,删除,遍历,大到小输出)【仿大佬写法】
  9. Bjarne Stroustrup语录[C++经验]
  10. java使用gridview,java反射,用于GridView
  11. redhat,centos Linux常用命令LS之常用功能
  12. C# 多线程系列(二)
  13. idea 远程调试_IDEA太强悍,针对调试器和代码分析器的改进,提前知道代码怎么跑...
  14. C++相对于C语言更加规范(1)
  15. 躲开Xilinx官网龟速的下载器
  16. java流程图是什么形状,流程判断(流程图判断框什么形状)
  17. stata 空间杜宾模型_空间面板数据模型及Stata实现
  18. 关于google拼音输入法的坑爹问题-IE浏览器浏览网页蓝屏等问题
  19. BC26:使用MQTT对接阿里云平台
  20. 查看git brach_Excel Go Brach – Excelebrations

热门文章

  1. 互信息的数学解释以及matlab编程
  2. C# Enum,Int,String的互相转换
  3. ARM的存储器映射与存储器重映射【转载】2009-12-14 10:29最近在用LPC2148,看到了一篇文章,感觉很有帮助,就转了过来。
  4. python 判断是否是int/string/类型的函数
  5. Unity3d Time的使用
  6. struts2采用convention-plugin实现零配置
  7. Linux 读取文件n行并删除方法
  8. 数据处理的两个基本问题---汇编学习笔记
  9. SecureCRT 或者 超级终端 始终无法ping通主机
  10. 第一课 计算机网络的分类,第一课-计算机网络基本组成