[bzoj4567] [loj#2012] [SCOI2016] 背单词
Description
\(Lweb\) 面对如山的英语单词,陷入了深深的沉思,「我怎么样才能快点学完,然后去玩三国杀呢?」。这时候睿智的凤老师从远处飘来,他送给了 \(Lweb\) 一本计划册和一大缸泡椒,然后凤老师告诉 \(Lweb\) ,我知道你要学习的单词总共有 \(n\) 个,现在我们从上往下完成计划表,对于一个序号为 \(x\) 的单词(序号 \(1...x-1\) 都已经被填入):
1.如果存在一个单词是它的后缀,并且当前没有被填入表内,那他需要吃 \(n \times n\) 颗泡椒才能学会;
2.当它的所有后缀都被填入表内的情况下,如果在 \(1...x-1\) 的位置上的单词都不是它的后缀,那么他吃 \(x\) 颗泡椒就能记住它;
3.当它的所有后缀都被填入表内的情况下,如果 \(1...x-1\) 的位置上存在是它后缀的单词,所有是它后缀的单词中,序号最大为 \(y\) ,那么他只要吃 \(x-y\) 颗泡椒就能把它记住。
\(Lweb\) 是一个吃到辣辣的东西会暴走的奇怪小朋友,所以请你帮助 \(Lweb\),寻找一种最优的填写单词方案,使得他记住这 \(n\) 个单词的情况下,吃最少的泡椒。
Input
输入一个整数 ,表示 \(Lweb\) 要学习的单词数。接下来 \(n\) 行,每行有一个单词(由小写字母构成,且保证任意单词两两互不相同)。
Output
\(Lweb\) 吃的最少泡椒数。
Sample Input
2
a
ba
Sample Output
2
HINT
\(1 \leq n \leq 10^5\),所有字符的长度总和 \(1 \leq |len| \leq 510000\)
想法
把所有串反过来,建在 \(trie\) 树上,形成一颗前缀树,那么原题中的后缀即这里的前缀
一个显然的贪心是所有串都在它所有前缀填入后再填,\(n \times n\) 的代价要不起。
相当于在树上进行遍历,使所有点的父节点都在子节点前访问,总代价是所有点与其父节点的访问时间差 的总和。
于是又一个贪心,每个点访问后按它所有子节点 \(size\) 的大小,从小到大依次访问。
很容易想到这个贪心,但咋证明是对的呢?【听说这是个经典问题,但网上也没看见多少证明啊(逃】
可以看 \(neither_nor\) 的证明 https://blog.csdn.net/neither_nor/article/details/51362523
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 110000;
typedef long long ll;
int n;
int fa[N],sz[N];
struct trie{
trie *ch[26];
int id;
}pool[N*5],*root;
int cnt;
void insert(char s[],int id){
trie *p=root;
int len=strlen(s);
for(int i=len-1;i>=0;i--){
if(!p->ch[s[i]-'a']) p->ch[s[i]-'a']=&pool[++cnt];
p=p->ch[s[i]-'a'];
}
p->id=id;
}
struct node{
node *nxt;
int v;
}pool2[N],*h[N];
int cnt2;
void addedge(int u,int v){
node *p=&pool2[++cnt2];
p->v=v;p->nxt=h[u];h[u]=p;
}
void dfs(trie *p,int cur){
int nc=p->id ? p->id : cur;
for(int i=0;i<26;i++)
if(p->ch[i])
dfs(p->ch[i],nc);
if(p->id){
sz[p->id]++;
fa[p->id]=cur;
sz[cur]+=sz[p->id];
addedge(cur,p->id);
}
}
ll ans;
int b[N],tot;
void work(int u){
for(node *p=h[u];p;p=p->nxt) work(p->v);
tot=0;
for(node *p=h[u];p;p=p->nxt) b[++tot]=sz[p->v];
sort(b+1,b+1+tot);
for(int i=1;i<=tot;i++)
ans+=1ll*b[i]*(tot-i);
ans+=tot;
}
int main()
{
char s[N];
scanf("%d",&n);
root=&pool[++cnt];
for(int i=1;i<=n;i++){
scanf("%s",s);
insert(s,i);
}
dfs(root,0);
ans=0; work(0);
printf("%lld\n",ans);
return 0;
}
[bzoj4567] [loj#2012] [SCOI2016] 背单词的更多相关文章
- 【BZOJ4567】[Scoi2016]背单词 Trie树+贪心
[BZOJ4567][Scoi2016]背单词 Description Lweb 面对如山的英语单词,陷入了深深的沉思,“我怎么样才能快点学完,然后去玩三国杀呢?”.这时候睿智 的凤老师从远处飘来,他 ...
- BZOJ4567[Scoi2016]背单词
4567: [Scoi2016]背单词 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 304 Solved: 114 [Submit][Status] ...
- 【bzoj4567】[Scoi2016]背单词
4567: [Scoi2016]背单词 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1123 Solved: 476[Submit][Status][ ...
- P3294 [SCOI2016]背单词
P3294 [SCOI2016]背单词 Trie+贪心 倒插进树+取出重建+子树处理+贪心遍历 倒插进树:把后缀转化为前缀,所以把字符串倒着插进Trie中 取出重建:重新建立一棵以单词为节点的树,如果 ...
- 4567: [Scoi2016]背单词
4567: [Scoi2016]背单词 https://www.lydsy.com/JudgeOnline/problem.php?id=4567 题意: 题意看了好久,最后在其他人的博客里看懂了的. ...
- [SCOI2016]背单词——trie树相关
题目描述 Lweb 面对如山的英语单词,陷入了深深的沉思,”我怎么样才能快点学完,然后去玩三国杀呢?“.这时候睿智的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计划册是长这样的: ...
- [SCOI2016]背单词 题解
背单词 https://www.luogu.com.cn/problem/P3294 前言: Trie树的省选题(瑟瑟发抖QAQ) 问题汇总:(请忽略) (1)对Trie字典树的运用不熟练 (2)没想 ...
- [BZOJ4567][SCOI2016]背单词(Trie+贪心)
1.题意表述十分难以理解,简单说就是:有n个单词,确定一个背的顺序,使总代价最小. 2.因为第(1)种情况的代价是n*n,这个代价比任何一种不出现第(1)种情况的方案都要大,所以最后肯定不会出现“背某 ...
- BZOJ4567 SCOI2016背单词(trie+贪心)
倒过来变成查询前缀.考虑怎么排序.第一条代价n*n就相当于inf,说明一个单词的所有前缀都要排在它前面.那么串的依赖关系就是trie的结构.二三条说明代价是Σidi-idfa,那么显然最后的编号应该是 ...
随机推荐
- 2018百度之星初赛B - A,D,F
总结:这一次的百度之星之行到这里也就结束了,充分的认识到了自己的不足啊...果然还是做的题太少,,见识的题型也还太少,对于STL的掌握还是不够到位啊!!(STL大法是真的好,建议大家认认真真的好好学学 ...
- Linux 内核同步 urb
不幸的是, 同步 urb 没有一个象中断, 控制, 和块 urb 的初始化函数. 因此它们必须在 驱动中"手动"初始化, 在它们可被提交给 USB 核心之前. 下面是一个如何正确初 ...
- Java基础系列8——IO流超详细总结
该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 在初学Java时,I ...
- js 处理json
json 分为两种结构 数组 对象 对象 { } 对象里的键值对 1.键值对之间用冒号链接 2.键必须用“”包裹 3.值如果是字符串 就用“”包裹 如果是数字 则不需要 4.键值对 ...
- Python7_内置函数总结
Python Built-In 函数: str(obj) :输入(对象),返回一个对象的string格式: isinstance(object,classinfo):判断一个对象是否是一个已知的类型, ...
- Java面向对象程序设计第14章3-8和第15章6
Java面向对象程序设计第14章3-8和第15章6 3.完成下面方法中的代码,要求建立一个缓冲区,将字节输入流中的内容转为字符串. import java.io.*; public class tes ...
- 015 Ceph的集群管理_1
一.理解Cluster Map cluster map由monitor维护,用于跟踪ceph集群状态 当client启动时,会连接monitor获取cluster map副本,发现所有其他组件的位置, ...
- 004 ceph存储池
介绍:前面已经使用deploy和ansble部署了ceph集群,现在对集群的池进行简单介绍和简单操作 一.部分概念 池是ceph存储集群的逻辑分区,用于存储对象 对象存储到池中时,使用CRUSH规则将 ...
- 【题解】NOIP2017逛公园(DP)
[题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...
- 洛谷$P$2286 宠物收养场 $[HNOI2004]$ $splay$
正解:$splay$ 解题报告: 传送门! $splay$板子,,,? 先考虑这题要实现些什么东西嘛$QwQ$ 其实只要实现一个东西?就查询数列中与给定数字相差最小的数,显然用$splay$查询前驱后 ...