【Trie】背单词

参考博客:

https://www.luogu.org/problemnew/solution/P3294

https://blog.csdn.net/VictoryCzt/article/details/87186287

【题意】

题意如果看不懂,请到第二个链接去推一推事例,你就明白这个过程了。

来自题解中glf大佬的解析。

这题目描述真是令人窒息。

3个条件的意思大概是这样:

(1).如果有单词作为现在正在填入的单词的后缀但并未填入,将花费n*n的代价。

(2).如果没有单词作为当前填入单词的后缀,代价为当前填入单词序号x

(3).如果所有作为该单词的后缀的单词之前都已经填入,那么代价为当前序号x-最后一个作为当前单词的后缀的单词的序号y。

【题解】

读懂题以后这道题还是比较明显的贪心。第1个条件提示一定是先将所有作为后缀的单词填入,因为如果不这样填不管怎么样代价都小于n*n。

由于询问的是后缀,所以后缀相同其实等价于反串的前缀相同,所以倒着建立一个trie树。

这时问题转化为求一棵树的拓扑序,满足儿子与父亲的编号差的和最小,所以可以直接贪心来做,简单观察发现,对于某一刻,无论选哪个节点,总代价都会增大目前能扫到的第一个标记点的总量。

要使总代价最少,那么这次选的点一定要使以后增加的点最小.

所以记录一下每个点能看到的,以及这一个子树下分支总量,一定优先处理分支更小的子树。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N  = 5e5 + 1e4 + 100;
 8 const int M = N * 26;
 9 long long ans = 0 ;
10 char s[M];
11 int n,idx;
12 int End[M],Son[N*26][26];
13 int pre[M],ID[M],Sz[M],num;
14 vector< int > G[N] ;
15 int Find( int x ){
16     if(pre[x]==x)return pre[x];
17     else return pre[x]=Find(pre[x]);
18 }
19 void Insert(int No){
20     int p = 0 ;
21     for(int i=strlen(s)-1; ~i ; i--){
22         int t = s[i] - ‘a‘;
23         if( !Son[p][t] ) Son[p][t] = ++idx;
24         p = Son[p][t];
25     }
26     End[p] = No ;
27 }
28 void Build(int x ){
29     for(int i=0;i<26;i++){
30         int t = Son[x][i] ;
31         if( t ) {
32             if( !End[t] ){
33                 pre[t] = Find(x);
34             }else{
35                 G[End[Find(x)]].push_back(End[t]);
36             }
37             Build(t);
38         }
39     }
40 }
41 int cmp(int u, int v ){
42     return Sz[u] < Sz[v] ;
43 }
44 void dfs_Size( int u ){
45     Sz[u] = 1 ;
46     for(auto x : G[u] ){
47         dfs_Size(x);
48         Sz[u] += Sz[x];
49     }
50     sort ( G[u].begin() , G[u].end() , cmp );
51 }
52 void dfs_Sum(int u){
53     ID[u] = num ++ ;
54     for( auto x : G[u] ){
55         ans += num - ID[u];
56         dfs_Sum(x);
57     }
58 }
59 void Check(int x)
60 {
61     for( auto v : G[x] )
62     {
63         cout<<v<<endl;
64         Check(v);
65     }
66 }
67 int main(){
68     scanf("%d",&n);
69     for(int i=1;i<=n;i++){
70         scanf("%s",s);
71         Insert(i);
72     }
73     for(int i=1;i<=idx;i++){
74         pre[i] = i ;
75     }
76     Build(0) ;
77     dfs_Size(0);
78     dfs_Sum(0);
79     //Check(0);
80     printf("%lld\n",ans);
81     return 0;
82 }

原文地址:https://www.cnblogs.com/Osea/p/11366898.html

时间: 2024-10-09 04:38:25

【Trie】背单词的相关文章

【BZOJ4567】[Scoi2016]背单词 Trie树+贪心

[BZOJ4567][Scoi2016]背单词 Description Lweb 面对如山的英语单词,陷入了深深的沉思,“我怎么样才能快点学完,然后去玩三国杀呢?”.这时候睿智 的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计划册是长这样的: ————— 序号  单词 ————— 1 2 …… n-2 n-1 n ————— 然后凤老师告诉 Lweb ,我知道你要学习的单词总共有 n 个,现在我们从上往下完成计划表,对于一个序号为 x 的单词(序号 1...x-1 都已经被

LibreOJ #2012. 「SCOI2016」背单词

二次联通门 : LibreOJ #2012. 「SCOI2016」背单词 /* LibreOJ #2012. 「SCOI2016」背单词 Trie + 贪心 大家都吐槽题目反人类 可我觉得还好,毕竟见的多了 不会做啊.. 正解好巧妙 考虑一下,发现一操作完全不必要,可以省去 因为所有的字符串的后缀关系会形成一个树 那么把字符串倒序插入Trie中 建树,每次向子树小的一个点转移即可 */ #include <cstdio> #include <algorithm> #include

bzoj4567【SCOI2016】背单词

4567: [Scoi2016]背单词 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 271  Solved: 103 [Submit][Status][Discuss] Description Lweb 面对如山的英语单词,陷入了深深的沉思,"我怎么样才能快点学完,然后去玩三国杀呢?".这时候睿智 的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计划册是长这样的: ----- 序号  单词 ----- 1 2 -

BNU27935——我爱背单词——————【数组模拟】

我爱背单词 Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main Prev Submit Status Statistics Discuss Next Type: None None   Graph Theory       2-SAT       Articulation/Bridge/Biconnected Component       Cycle

洛谷 P2353 背单词

题目背景 小明对英语一窍不通,令老师十分头疼.于是期末考试前夕,小明被逼着开始背单词…… 题目描述 老师给了小明一篇长度为N的英语文章,然后让小明背M个单词.为了确保小明不会在背单词时睡着,老师会向他提Q个问题,每次老师随机选择一个区间L..R,小明要回答在这段文字中他背过的单词总共出现过多少次. 输入输出格式 输入格式: 第一行两个整数M.Q如前所述.第二行为英语文章.接下来M行每行一个需要背的单词.接下来Q行每行一个询问,包含两个整数L.R(含端点),即给定的文字区间. 输出格式: Q行,对

P3294 [SCOI2016]背单词

P3294 [SCOI2016]背单词 Trie+贪心 倒插进树+取出重建+子树处理+贪心遍历 倒插进树:把后缀转化为前缀,所以把字符串倒着插进Trie中 取出重建:重新建立一棵以单词为节点的树,如果存在包含(前缀)关系就连边 子树处理:处理出每棵树的大小用于贪心 贪心遍历:遍历整棵新树,累加答案 关于贪心:每次找到最小的子树统计答案 end. #include<iostream> #include<cstdio> #include<cstring> #include&

和我一起开发Android应用(三)——“悦词-i背单词”词典功能实现

接上一讲.本节我们把词典功能基本实现,首先上一个效果图,我发现大家比较关心界面方面的东西,我之前写的一个关于QQ界面的项目就很受欢迎,当然我现在能写出远比那个好看的界面.但是我想一个应用最核心的东西不完全在界面,一个好的创意,一个好的后台服务才是成功的关键,这也是我不断学习的方向. 另外我发现在百度搜“悦词背单词91”搜索结果全是我在博客园的博文了...所以我把这个项目在91应用市场的下载地址粘上来吧,十分欢迎大家试用一下,有什么改进的意见请写在下面的评论里!地址:http://apk.91.c

bing背单词交互流程--Chongyang Bai

昨天和travis,钟秋开会确认了bing背单词的手机界面交互流程.我在这里简单描述一下,设计页面暂时不能贴出来,期待大家的宝贵意见 b( ̄▽ ̄)d. 单词本浏览界面:单词本被分为两类,用户单词本和单词书.每个单词本条目有一个小图标,点击图标则进入单词总览,点击条目其它部分则展开单词本的统计信息和学习情况. 单词本展开子页面:除了统计信息(如总词数,已学词数等)和学习情况外,还有两个按钮,开始学习和更改计划.若选择更改计划,则进入长期背单词计划设置,比如完成天数:若从未设定过计划,则点击开始背词

和我一起开发Android应用(二)——“悦词-i背单词”项目功能分析

好几天没有更新了,给关心这个系列的朋友们说声抱歉.今天我们开始第二节,项目功能分析.因为这个背单词软件虽说功能比较简单,但要真正实现起来也挺麻烦的.所以今天我们首先分析一下这个应用的功能,然后逐条慢慢实现. PS:这款应用已经上线91助手,百度移动应用和应用宝,有兴趣下来研究的可以百度搜索“悦词i背单词91”就可找到,我想真正用一下这个应用再看这个教程会有比较直观的理解.好废话不多讲,进入正题. 功能分析: 功能1.查单词. 实现方法:金山词霸开放平台提供了一个开放API,通过Http访问金山词

和我一起开发Android应用(一)——开发一款安卓多功能背单词软件

大家好,很久没有在博客园写过东西.前一段时间尝试学过一段时间cocos2d,但是由于学习资料有限,文档较少,一直难有进展,因此在刚刚过去的三周里,我又回到了我的老本行:java ,Android.在假期里我算是正式开发了我的第一个安卓应用: i背单词.经过三个星期的磕磕绊绊,终于写出一个较稳定的版本,现在这款应用已经成功上架GooglePlay,并且很快会在百度移动应用和安智网上架.当然由于这款软件只是由我个人维护,我也不奢求会有多大的下载量了呵呵,但我想有必要把这短时间开发应用的体会做一个总结