题目描述可能稍有偏差,但实质上是一样的。

看下面

题目大意

题面这么长,先说说题意吧。

就是有一个操作系统,他的存储方式是树形的。其中分为文件和目录(文件夹)每一个子目录下只能存储 $K$ 个文件或目录。并且有 $K$ 个指针分别指向这 $K$ 个文件或文件夹。每一个指针都有一个访问时间 $P$。

然后每一个文件或目录都有一个访问时间,文件和目录的访问时间计算方式不相同

  • 文件:访问其所有上级目录(就是这个文件访问路径上的文件夹)的访问时间加上这个文件的指针的访问时间。
  • 文件夹:它的各级子目录下文件的个数 $\times $ 它的指针的访问时间。通俗一点就是它的子树上的文件的个数为 $x$,它的指针访问时间是 $y$ 那么它的访问时间就是 $x\times y$。这里要说一下题面描述出了锅,最起码我现在看是这样的。

现在你需要计算出给出的 $N$ 个文件的最小访问时间总和。

解题思路

我看了Vijos上的题解表示并没有看懂,于是问问机房的dalao。dalao就是dalao。

这是一道树形DP。首先要明白一个贪心策略。在同一层子目录下,如果现在的剩余空间已经无法容纳剩下的文件那么我们必然是需要在开一个文件夹进行存储的。那这个文件夹开的位置的指针访问时间越小越好。因为如果它是一个文件夹的话,它对答案的影响会随着它的子目录中文件的数量增加而成倍增加。所以要尽量的小。这就是一个贪心的策略,显然在输入的时候是需要对指针的访问时间从小到大排序的。

接下来做树形dp。先看下代码,我们一段一段的讲。

int main() {
scanf("%d%d", &n, &k);
for(int i=; i<=k; i++)
scanf("%d", &p[i]);
sort(p+, p++k);
printf("%d", dp(n, , n-));
}

排序这一部分自然是不用多说了,上面已经说过了。

再来看dp函数

inline int dp(int x, int y, int l) {
if(x == ) {
f[x][y] = p[y];
return f[x][y];
}
if(y == k) {
f[x][y] = p[y] * x * x + dp(x, , x-);
return f[x][y];
}
int tmp = k-y+;
if(tmp * l < x)
return INF;
if(f[x][y]) return f[x][y];
tmp = (x-)/tmp + ;
for(int i=tmp; i<=l; i++) {
if(i == )
f[x][y] = p[y] + dp(x-, y+, x-);
else
f[x][y] = MIN(f[x][y], dp(x-i, y+, x-i-) + dp(i, , i-) + p[y] * i * i);
}
return f[x][y];
}

$x$ 表示还剩下多少个文件没有被安排。$y$ 表示现在用到的是第 $y$ 个指针。$f[x][y]$ 表示还剩 $x$ 个文件用第 $y$ 个指针的最小的访问时间。

显然如果 $x == 1$ 的话,就直接将现在这个指针的时间给它就好了。如果 $y==k$ 的话,说明 $k$ 个指针已经用到了最后一个那肯定是要建一个文件夹。

这里的 $p[y]*x*x$ 的含义呢,是将这个文件夹的访问时间计算出来并且它之后会产生 $x$ 次影响,将这 $x$ 次影响在这里直接计算出来。

$l$ 表示层数,是最多还能伸下去安排几层。$tmp$ 那个地方是一个小剪枝。如果剩余的内存还不够将这 $x$ 个文件安排好的话就直接反回 $inf$。

往后的状态转移,如果只剩下一个需要安排的话,那就直接安排上。否则的话就开一个文件夹,把除文件夹外的剩余空间进行分配,并且往下深入一层。

附上代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = , INF = ;
int n, k, p[], f[maxn][maxn];
inline int MIN(int x, int y) {
if(!x) return y;
else return min(x, y);
}
inline int dp(int x, int y, int l) {
if(x == ) {
f[x][y] = p[y];
return f[x][y];
}
if(y == k) {
f[x][y] = p[y] * x * x + dp(x, , x-);
return f[x][y];
}
int tmp = k-y+;
if(tmp * l < x)
return INF;
if(f[x][y]) return f[x][y];
tmp = (x-)/tmp + ;
for(int i=tmp; i<=l; i++) {
if(i == )
f[x][y] = p[y] + dp(x-, y+, x-);
else
f[x][y] = MIN(f[x][y], dp(x-i, y+, x-i-) + dp(i, , i-) + p[y] * i * i);
}
return f[x][y];
}
int main() {
scanf("%d%d", &n, &k);
for(int i=; i<=k; i++)
scanf("%d", &p[i]);
sort(p+, p++k);
printf("%d", dp(n, , n-));
}

「 Luogu P2230 」X 「 Vijos 1142 」 HXOS系统的更多相关文章

  1. 「Luogu P2468 [SDOI2010]粟粟的书架」

    这道题分为两个部分 Part1 前置芝士 前缀和(后缀和,二维前缀和):可以预处理一下数据. 二分查找:可以在较短的时间内找出答案. 具体做法 可以发现\(R,C\)不大,只有\(200\),于是可以 ...

  2. 「Luogu P3078 [USACO13MAR]扑克牌型Poker Hands」

    本题有\(O(N)\)的优秀做法,但是因为在考场上不一定能想到,就来分享一种\(O(N\log_2N)\)的做法.虽然有点慢,但是可以过. 前置芝士 线段树:提高组及以上必备内容,不会的同学可以学习一 ...

  3. 「Luogu P3820 小D的地下温泉」

    这道题的考点比较多. 前置芝士 BFS(DFS),这两种算法在这道题中并没有什么特别突出的地方,基本就是自己看心情写(本文以DFS为准,所以我心情是好是坏呢?) 连通块,可以将每一个温泉看作一个连通块 ...

  4. 「Luogu P2253 好一个一中腰鼓!」

    就这道题的理论难度来说绿题是有点低了,但是这道题的实际难度来看,顶多黄题,所以建议加强数据或出数据升级版. 前置芝士 线段树:具体可以看我的另一篇文章. 具体做法 暴力的方法想必都会,所以来讲一下正解 ...

  5. Git 执行 「fork 出来的仓库」和「最新版本的原仓库」内容同步更新

    当我们在 GitHub 上 fork 出一个仓库后,如果原仓库更新了,此时怎样才能保证我们 fork 出来的仓库和原仓库内容一致呢?我们一般关注的是仓库的 master(主干分支)的内容,通过以下步骤 ...

  6. FileUpload控件「批次上传 / 多档案同时上传」的范例--以「流水号」产生「变量名称」

    原文出處  http://www.dotblogs.com.tw/mis2000lab/archive/2013/08/19/multiple_fileupload_asp_net_20130819. ...

  7. Java的参数传递是「值传递」还是「引用传递」?

    关于Java传参时是引用传递还是值传递,一直是一个讨论比较多的话题. 有人说Java中只有值传递,也有人说值传递和引用传递都是存在的,比较容易让人产生疑问. 关于值传递和引用传递其实需要分情况看待. ...

  8. Linux 小知识翻译 - 「Unix」和「兼容Unix的OS」

    经常有人会问「Linux和Unix有什么区别?」,「Linux就是Unix吗?」. 回答一般都是「Linux是仿照Unix而开发的OS」,「Linux和Unix相似但不是一种OS」之类的. 关于「Li ...

  9. Linux 小知识翻译 - 「Linux」和「发行版」之间的关系

    「Linux」本来指的仅仅是内核.5年之前大多都是这么认为的,但是最近不这么说了. 最近一般都说「Linux」是个 OS,这里的OS,不仅仅是内核,而是指电脑的整体环境(除了内核,还包括一些外围的软件 ...

随机推荐

  1. tracert 路由跟踪程序

    C:\Users\Administrator>tracert 10.0.0.1 通过最多 30 个跃点跟踪到 10.0.0.1 的路由 1 <1 毫秒 1 ms 3 ms 192.168. ...

  2. 【BZOJ 3732】 Network

    [题目链接] 点击打开链接 [算法] 求出这个图的最小生成树,对于每次询问,用倍增法求出最近公共祖先,查询最小生成树上两点路径上的最大值 算法的正确性?            假设x和y在最小生成树中 ...

  3. IJ:Eclipse快捷键大全

    ylbtech-IJ:Eclipse快捷键大全 1.返回顶部 1. Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加 ...

  4. matlab采用mex编译多个cpp文件

    最近在看matlab code时,由于本人使用的是64系统,而code中的mex文件时在32位系统上编译的,所以需要重新自己编译maxflowmex.cpp,但是直接mex maxflowmex.cp ...

  5. bzoj3339

    线段树+离线 这种题既可以用莫队做也可以用线段树做,跟hh的项链差不多 首先我们处里出前缀mex,也就是1->i的mex值,再预处理出每个数下一次出现的位置,然后把每个前缀mex插入线段树,每个 ...

  6. bzoj4870

    http://www.lydsy.com/JudgeOnline/problem.php?id=4870 矩阵快速幂... 人话题意:从nk个物品里选模k余r个物品,问方案数模P 那么我们有方程 f[ ...

  7. 让你彻底明白JAVA中堆与栈的区别

    原文地址:http://www.2cto.com/kf/201302/190704.html 简单的说: Java把内存划分成两种:一种是栈内存,一种是堆内存. 在函数中定义的一些基本类型的变量和对象 ...

  8. J20170602-ts

    アソシエーション association   n. 联想; 协会,社团; 联合,联系; アンケート    英文是questionnaire

  9. bzoj 1801: [Ahoi2009]chess 中国象棋【dp】

    注意到一行只能放012个炮,我们只需要知道列的状态,不用状压行 所以设f[i][j][k]表示前i行有j列有1个炮,有k列有2个炮的方案数 然后分情况讨论转移就行了 #include<cstdi ...

  10. linux vi 块操作、多窗口

    vim 块选择v:字符选择或者行选择[ctrl]+v: 块选择y:将反白的地方复制d:将反白的地方删除 多窗口:sp {filename} 打开一个新的窗口[ctrl]+w+j或者[ctrl]+w+向 ...