题目传送

阅读理解题题意解释可以看这位大佬的博客

  发现求后缀与倒序求前缀是等价的,而找前缀自然就想到了trie树。将所有字符串翻转后再建入trie树中,再对每一个字符串翻转后从trie树中找前缀,就能找到一个字符串的所有后缀了。

  由第三种情况知我们要想最小化总代价,则最小化一个字符串与最靠近它的后缀间的距离应该也是一个要考虑的因素。其实一个串最近的后缀其实一定是它的所有后缀中长度最大的,因为它的后缀中长度短的也一定是长度大的后缀,并且还要避免第一种情况的出现(即序列在一个字符串后面的串中不能有这个字符串的后缀)。故我们只要知道每个字符串最长的后缀就好。若一个串是另一个串的后缀,则可以从这个串向另一个串连一条有向边,则最终会形成一个森林。

  这时避免了第一种情况后,还有两种情况。我们做了这么多题,知道一种情况总应该比多种情况好做。故考虑将两种情况转化为一种。发现如果我们在所有题目给出的字符串的基础上再加入一个处于序列第0个位置的空串,那么第二种情况也就转化为了第三种情况,并且对答案没有影响。这种转化对于当前的森林,只要再建个标号为0的空串节点连向所有树的根就好了。

  此时问题就转化为:给树的节点编号,要求父亲节点的序号比儿子节点小,且根节点的序号为0,并使得儿子节点的编号减父亲节点编号的差的和最小,求最小的和。考虑怎么选点编号。作者一开始也懵的一逼于是看了看这位大佬博客关于选法的证明部分(“考虑建出……Q.E.D”)终于明白如果选到了一个点,就要一口气把它的子树都选了,并且优先选子树大小最小的儿子。dfs就搞定了呀。至于对某个点的儿子从子树大小小的往大的选,可以用堆维护。

具体实现请看代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<queue> #define max(a,b) ((a)>(b)?(a):(b)) using namespace std; const int N=,LEN=; int tree[][],cnt,n,l,dfs;
int ed[LEN],in[N],lst[N],to[N],nxt[N],ecnt,dfn[N]; long long siz[N],ans; string word[N]; char ch; inline int read()
{
int x=;
ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<)+(x<<)+(ch^),ch=getchar();
return x;
} inline void getstring(string &a)
{
a="";
ch=getchar();
while(ch<'a'||ch>'z')
ch=getchar();
while(ch>='a'&&ch<='z')
a+=ch,ch=getchar();
} inline void insert(const string &a,int j)
{
l=a.length();
int now=,num;
for(int i=l-;i>=;--i)//要将字符串倒序插入trie树中
{
num=a[i]-'a';
if(!tree[now][num])
tree[now][num]=++cnt;
now=tree[now][num];
}
ed[now]=j;
} inline void addedge(int u,int v)
{
nxt[++ecnt]=lst[u];
lst[u]=ecnt;
to[ecnt]=v;
} inline int fin(const string &a)
{
int now=,num,ret=-;
l=a.length();
for(int i=l-;i>=;--i)//查后缀就是倒序查前缀
{
num=a[i]-'a';
if(!tree[now][num])
return ret;
now=tree[now][num];
if(ed[now]&&i)
ret=ed[now];
}
return ret;
} void dfssiz(int u)
{
siz[u]=;
for(int e=lst[u];e;e=nxt[e])
{
dfssiz(to[e]);
siz[u]+=siz[to[e]];
}
} struct node{
int lar,ord;
}head; inline bool operator < (const node &a,const node &b)
{
return a.lar>b.lar;//大根堆变小根堆
} void dfsans(int u)
{
priority_queue<node>hep;
for(int e=lst[u];e;e=nxt[e])
{
hep.push((node){siz[to[e]],to[e]});
}
while(!hep.empty())
{
head=hep.top();
hep.pop();
dfn[head.ord]=++dfs;//编号过程
ans+=dfn[head.ord]-dfn[u];
dfsans(head.ord);
}
} int main()
{
n=read();
for(int i=;i<=n;++i)
{
getstring(word[i]);//字符串的读入优化
insert(word[i],i);
}
int u;
for(int i=;i<=n;++i)
{
u=fin(word[i]);
if(u!=-)
{
addedge(u,i);
in[i]++;
}
}
for(int i=;i<=n;++i)
if(!in[i])//没有入度的点就是森林中树的根
addedge(,i);
dfssiz();//求一下每个点的子树大小。
dfsans();//统计答案。
printf("%lld",ans);
return ;
}

AC代码

洛谷P3294 [SCOI2016]背单词——题解的更多相关文章

  1. P3294 [SCOI2016]背单词

    P3294 [SCOI2016]背单词 Trie+贪心 倒插进树+取出重建+子树处理+贪心遍历 倒插进树:把后缀转化为前缀,所以把字符串倒着插进Trie中 取出重建:重新建立一棵以单词为节点的树,如果 ...

  2. [SCOI2016]背单词 题解

    背单词 https://www.luogu.com.cn/problem/P3294 前言: Trie树的省选题(瑟瑟发抖QAQ) 问题汇总:(请忽略) (1)对Trie字典树的运用不熟练 (2)没想 ...

  3. BZOJ4567:[SCOI2016]背单词——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4567 Lweb 面对如山的英语单词,陷入了深深的沉思,“我怎么样才能快点学完,然后去玩三国杀呢?” ...

  4. [luogu] P3294 [SCOI2016]背单词 (贪心)

    题目描述 Lweb 面对如山的英语单词,陷入了深深的沉思,"我怎么样才能快点学完,然后去玩三国杀呢?".这时候睿智的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他 ...

  5. 洛谷P3295 [SCOI2016]萌萌哒 题解

    洛谷P3295 [SCOI2016]萌萌哒 题目描述 公式粘过来就乱了,还是去洛谷看题吧 分析 如果暴力解决的话就是使用并查集把位数相同的数位并在一起.比如区间[1,2]和区间[3,4]的数字完全相同 ...

  6. BZOJ4567[Scoi2016]背单词

    4567: [Scoi2016]背单词 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 304 Solved: 114 [Submit][Status] ...

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

    [BZOJ4567][Scoi2016]背单词 Description Lweb 面对如山的英语单词,陷入了深深的沉思,“我怎么样才能快点学完,然后去玩三国杀呢?”.这时候睿智 的凤老师从远处飘来,他 ...

  8. 【bzoj4567】[Scoi2016]背单词

    4567: [Scoi2016]背单词 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1123 Solved: 476[Submit][Status][ ...

  9. 洛谷P1783 海滩防御 分析+题解代码

    洛谷P1783 海滩防御 分析+题解代码 题目描述: WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和 ...

随机推荐

  1. 什么是分布式关系型数据库服务 DRDS

    DRDS 产品简介 DRDS 是一款基于 MySQL 存储.采用分库分表技术进行水平扩展的分布式 OLTP 数据库服务产品,支持 RDS for MySQL 以及 POLARDB for MySQL, ...

  2. mysql添加索引造成的影响

    尽管添加索引可以优化SQL语句的性能,但是添加索引的同时也会带来不小的开销.尤其是在有大量的索引的情况下. mysql添加索引造成的影响如下: 1.DML(数据操作语言)影响,在表上添加缩影会直接影响 ...

  3. vs nuget找不到包

    nuget.org https://api.nuget.org/v3/index.json

  4. loj 2392「JOISC 2017 Day 1」烟花棒

    loj 答案显然满足二分性,先二分一个速度\(v\) 然后显然所有没有点火的都会往中间点火的人方向走,并且如果两个人相遇不会马上点火,要等到火快熄灭的时候才点火,所以这两个人之后应该在一起行动.另外有 ...

  5. 13 Python之第一类对象闭包和迭代器

      def fn():     print("我叫fn") fn() print(fn)## <function fn at 0x0000000001D12E18> f ...

  6. ArcGis之popup列表字段自定义

    ArcGis之popup列表字段自定义 featureLayer图层中可以使用popupTemplate属性添加弹窗. API:https://developers.arcgis.com/javasc ...

  7. Vue实例:vue2.0+ElementUI框架开发pc项目

    开发前准备 vue.js2.0中文,项目所使用的js框架 vue-router,vue.js配套路由 vuex,状态管理 Element,UI框架 1,根据官方指引,构建项目框架 安装vue npm ...

  8. mybatis postgresql insert后返回自增id

    在使用mybatis + postgresql,我们有时在插入数据时需要返回自增id的值,此时在插入时,可以按照以下例子来编写mapper文件 <insert id="insertUs ...

  9. Jenkins 入门系列--jenkins 介绍

    第一章 Jenkins是什么? Jenkins 是一个可扩展的持续集成引擎. 主要用于: l 持续.自动地构建/测试软件项目. l 监控一些定时执行的任务. Jenkins拥有的特性包括: l 易于安 ...

  10. parfile解决exp时tables过多问题

    parfile 一般用于表数据过大.使用导出.导入命令参数过多等场景: 在对oracle数据库使用exp命令导出数据时,如果tables=后面跟的表比较多,就是导致命令行放不下,从而不能导出.百度一把 ...