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. html中图片自适应浏览器和屏幕,宽度高度自适应

    1.(宽度自适应):在网页代码的头部,加入一行viewport元标签. <meta name="viewport" content="width=device-wi ...

  2. document,element,dom对象api详解

    Document对象: 根元素的访问,也就是HTML标签的访问.使用document.documentElement访问根对象. 使用Document对象查找对象 getElementById():通 ...

  3. LINUX硬件查看命令

    1.查看系统PCI设备 lspci lspci -v   显示更详细的PCI设备信息 2.查看CPU信息 more / proc /cpuinfo 3.查看系统内存信息 more /proc /mem ...

  4. 生活中的goto

    if(你是个傻逼?){ out.println("继续你的傻逼生活吧!"); }else(你不是傻逼?){ out.println("你说不是都不是啊,继续你的傻逼生活吧 ...

  5. 枚举当前环境中打开的所有IE

    IE程序是属于Shell的一个应用程序,要枚举当前打开的所有IE程序窗口,可以通过ShellWindows集合来打开属于Shell的当前的窗口的集合. 首先添加程序需要的头文件和tlb库 //#imp ...

  6. 网页添加提示音,用setInterval

    如果一条数据通过审核了,修改数据库中一个值,用户怎么异步动态知道自己的记录通过审核了呢,我是通过音乐和提示的方式. 网页中添加如下代码: <style> #notify { positio ...

  7. 【其他】UTF-8带签名与不带签名

    在 Visual Web Developer 另存为文件时,有编码选项,其中有: Unicode (UTF-8 with signature) - Codepage 65001 Unicode (UT ...

  8. bzoj2257[POI2011]Programming Contest

    首先可以费用流建图,左边一堆点表示人,右边一堆点表示题,源点向每个人连floor(t/r)条边,费用依次为r,2r,3r….然后写了一个卡不过去,动态加边也卡不过去,然后我想:这里一定有一些不为人知的 ...

  9. 【bzoj1334】[Baltic2008]Elect 背包dp

    题目描述 N个政党要组成一个联合内阁,每个党都有自己的席位数. 现在希望你找出一种方案,你选中的党的席位数要大于总数的一半,并且联合内阁的席位数越多越好. 对于一个联合内阁,如果某个政党退出后,其它党 ...

  10. Python替换字符串中的反斜杠\

    s = 'cdp\nd' result = eval(repr(s).replace('\\', '@')) print(result) repr() 函数可以将字符串转换为python的原始字符串( ...