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

看下面

题目大意

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

就是有一个操作系统,他的存储方式是树形的。其中分为文件和目录(文件夹)每一个子目录下只能存储 $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. Oracle利用游标返回结果集的的例子(C#)...(最爱)

    引用地址:http://www.alixixi.com/program/a/2008050727634.shtml   本例在VS2005+Oracle 92010 + WindowsXp Sp2测试 ...

  2. [翻译]NUnit---Condition Asserts && Comparisons Asserts && Type Asserts (五)

    网址:http://www.cnblogs.com/kim01/archive/2013/03/31/2991597.html Condition Asserts 测试指定条件的方法称作条件测试,测试 ...

  3. linux 和win7 双系统模式下 忘记win7 密码的修改方法

    首先登陆linux系统,在linux 系统下找到win7系统的安装盘(比如为C盘), (1)进入到C://windows/system32下 找到osk.exe 文件,并将其剪切到其他的地方(记住这个 ...

  4. 牛客网9.9比赛 C 保护

    题目大意: n个城市构成一个树 m支军队 每只军队守卫 在xi到yi的最短路径上的城市 q个重要人物从vi出发 找到离根最近的点使从vi到这个点上所有路径都可以被至少ki个军队完全覆盖 输出每个答案的 ...

  5. [原创]桓泽学音频编解码(13):AC3 位分配模块算法分析

    [原创]桓泽学音频编解码(1):MPEG1 MP3 系统算法分析 [原创]桓泽学音频编解码(2):AC3/Dolby Digital 系统算法分析 [原创]桓泽学音频编解码(3):AAC 系统算法分析 ...

  6. 理解C#泛型(转)

    理解C#泛型 http://www.cnblogs.com/wilber2013/p/4292240.html 泛型中的类型约束和类型推断 http://www.cnblogs.com/wilber2 ...

  7. bzoj 4756: [Usaco2017 Jan]Promotion Counting【dfs+树状数组】

    思路还是挺好玩的 首先简单粗暴的想法是dfs然后用离散化权值树状数组维护,但是这样有个问题就是这个全局的权值树状数组里并不一定都是当前点子树里的 第一反应是改树状数组,但是显然不太现实,但是可以这样想 ...

  8. 清北考前刷题day2下午好

    #include<iostream> #include<cstdio> #include<cstring> #include<stack> #defin ...

  9. P4128 [SHOI2006]有色图

    传送门 数学渣渣看题解看得想死Ծ‸Ծ 首先发现这玩意儿看着很像polya定理 \[L=\frac{1}{|G|}\sum_{i\in G}m^{w(i)}\] 然而polya定理只能用来求点的置换,边 ...

  10. (DP)51NOD 1085 背包问题

    在N件物品取出若干件放在容量为W的背包里,每件物品的体积为W1,W2……Wn(Wi为整数),与之相对应的价值为P1,P2……Pn(Pi为整数).求背包能够容纳的最大价值. Input 第1行,2个整数 ...