Brief Description

  • 给你N个互不相同的字符串,记\(S_i\)为第i个字符串,现在要求你指定N个串的出现顺序,我们用\(V_i\)表示第i个字符串是第几个出现的,则V为1到N的一个排列。我们希望你指定的出现顺序可以使总代价最小
  • 一个出现顺序的代价的计算方法如下依次考虑第i个串\(S_i\)对代价的贡献:
    • 假如存在一个串\(S_j\), \(S_j\)为\(S_i\)的后缀:

      • 假如存在一个串\(S_j\), \(S_j\)为\(S_i\)的后缀,且\(V_j>V_i\)则第i个串对代价的贡献为\(N\times N\)
      • 否则,记\(P_i\)为所有满足\(S_j\)为\(S_i\)的后缀的j中\(V_j\)的最大值,第i个串对代价的贡献为\(V_i-P_i\)
    • 否则,如果不存在一个串\(S_j\),使得\(S_j\)为\(S_i\)的后缀,则第i个串对代价的贡献为\(V_i\)
    • 你需要输出这个最小的总代价.

Algorithm Design

首先可以证明第一个条件是没有用处的.

然后我们视后缀为一种偏序关系, 那么字符串就构成了一颗树, 那么问题就转化成了给树上每个节点标号使得他的标号减去他的父亲的标号的和最小.

这是一个经典的贪心问题. 我们选择每次都选择最小的size子树进行标号, 不难证明这样做的correctness.

Code

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#define ll long long
#define pa std::pair<int, int>
const int maxn = 100000 + 100;
const int maxlen = 520000 + 100;
int n;
struct edge {
int to, next;
} e[maxn << 1];
char str[maxlen];
int rt = 1, sz = 1, ch[maxlen][26], len, id[maxlen], tot, head[maxn],
size[maxn], f[maxn], cnt, fa[maxn];
std::vector<pa> v[maxn << 1];
inline void ins(int id) {
int p = rt;
for (int i = len; i >= 1; i--) {
int x = str[i] - 'a';
if (!ch[p][x]) {
ch[p][x] = ++sz;
}
p = ch[p][x];
}
::id[p] = id;
}
inline void add_edge(int u, int v) {
e[++tot].to = v;
e[tot].next = head[u];
fa[v] = u;
head[u] = tot;
}
void dfs(int x, int fa) {
if (id[x]) {
add_edge(fa, id[x]);
fa = id[x];
}
for (int i = 0; i < 26; i++) {
if (ch[x][i])
dfs(ch[x][i], fa);
}
}
void dfs2(int x) {
size[x] = 1;
for (int i = head[x]; i; i = e[i].next) {
int y = e[i].to;
dfs2(y);
v[x].push_back(std::make_pair(size[y], y));
size[x] += size[y];
}
std::sort(v[x].begin(), v[x].end());
}
void getf(int x) {
if (x)
f[x] = ++cnt;
for (int i = 0; i < v[x].size(); i++)
getf(v[x][i].second);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input", "r", stdin);
#endif
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%s", str + 1);
len = strlen(str + 1);
ins(i);
}
dfs(1, 0);
dfs2(0);
getf(0);
ll ans = 0;
for (int i = 1; i <= n; i++)
ans += f[i] - f[fa[i]];
printf("%lld", ans);
}

[bzoj4567][Scoi2016]背单词-Trie+贪心+模型转化的更多相关文章

  1. [BZOJ4567][SCOI2016]背单词(Trie+贪心)

    1.题意表述十分难以理解,简单说就是:有n个单词,确定一个背的顺序,使总代价最小. 2.因为第(1)种情况的代价是n*n,这个代价比任何一种不出现第(1)种情况的方案都要大,所以最后肯定不会出现“背某 ...

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

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

  3. BZOJ4567[Scoi2016]背单词

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

  4. [SCOI2016]背单词——trie树相关

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

  5. BZOJ4567 [Scoi2016]背单词 【trie树 + 贪心】

    题目链接 BZOJ4567 题解 题意真是鬼畜= = 意思就是说我们应先将一个串的所有后缀都插入之后再插入这个串,产生代价为其到上一个后缀的距离 我们翻转一下串,转化为前缀,就可以建\(trie\)树 ...

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

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

  7. [bzoj4567][Scoi2016][背单词] (贪心+trie树)

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

  8. 2019.03.25 bzoj4567: [Scoi2016]背单词(trie+贪心)

    传送门 题意: 给你n个字符串,不同的排列有不同的代价,代价按照如下方式计算(字符串s的位置为x): 1.排在s后面的字符串有s的后缀,则代价为n^2: 2.排在s前面的字符串有s的后缀,且没有排在s ...

  9. BZOJ 4567 [SCOI2016]背单词 (Trie树、贪心)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4567 题解: 显然答案一定小于\(n\times n\), 字符串倒过来变成前缀建Tr ...

随机推荐

  1. osg::Vec2 Vec3 Vec4

    osg::Vec2可以用于保存2D纹理坐标. osg::Vec3是一个三维浮点数数组. osg::Vec4用于保存颜色数据.

  2. 判断集合不为空Java

    list.size>0判断集合size是否大于0 list.isEmpty()判断集合是否为空,返回布尔值

  3. 禁止移动端input弹出软键盘

    在做三级联动,或者一些时间插件的时候总是弹出软键盘,用下面的方法就可以禁用掉,废话不多说直接上代码. HTML代码 <div class=""> <div> ...

  4. RT-thread国产实时操作系统概述

    RT-Thread实时操作系统是一个分层的操作系统,它包括了: • 组件层components,这些是基于RT-Thread核心基础上的外围组件,把一些功能模块划分成独立的一个个组件模块,做到组件与组 ...

  5. P3385 【模板】负环

    题目描述 暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索 输入输出格式 输入格式: 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个顶点,M条边 ...

  6. (五)Redis集合Set操作

    Set全部命令如下: sadd key member1 member2 ... # 将一个或多个member元素加入到集合key中,已经存在于集合的member元素将被忽略 spop key # 移除 ...

  7. [bzoj] 2657 ZJOI2012 旅游 || bfs

    原题 题意: 一个多边形,三角剖分,求一条对角线最多能经过多少三角形 题解: 因为不涉及坐标之类的,所以根几何肯定一点关系都没有. 我们会发现,对于有共边的两个三角形,可以被同一条线穿过,而这就相当于 ...

  8. 从零开始学Linux系统(四)之Vi/Vim操作指令

    模式切换: 编辑模式 <-- [:]<--命令模式 -->[a.i.o A.I.O]-->  插入模式 编辑模式操作: 设置行号  :set nu   :set nonu 复制 ...

  9. node记录

    集中管理 require('sequelize'); require('node-schedule')

  10. POJ 1661 DP

    Help Jimmy Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 11071   Accepted: 3607 Descr ...