今天是因为David Lee正好讲这个题的类似题,我才做了一下。

本题是world final 2016的一道水……

题目地址如下

http://www.lydsy.com/JudgeOnline/problem.php?id=4619.

这道题目让我们求为格式化所有硬盘所需要买的最小的额外空间。

这道题目很容易能看出来是一道贪心题目(据David Lee说还有一种做法是二分+贪心,不过qdez的师天硕stonepage和我Icontofig都觉得二分+贪心有些麻烦,然而stonepage不打算写,那就由我来写这一篇题解报告)。

那我们该怎么贪心呢?

第一种想法:我们看格式化后与格式化前的差值的大小来拍一遍序,然后加起来(剩余空间)看看最后我们需要多少额外空间(剩余空间是负数)。这个想法很容易被Hack掉,自己手写一组加起来大于0的就可以Hack,因为你一开始的磁盘空间是0

第二种想法:我们先把格式化后与格式化前的差值大于0的加在一起,然后再根据每个磁盘的a值升序操作剩下的。这个也很容易hack掉,比如突然就来了一个格式化前空间非常大的,这种做法就懵逼了。

第三种想法:那我把第二种想法倒过来,行不行呢?显然不行,有些数据随随便便就可以hack掉你。

那应该怎么做?

正解:

我们对于输入的数据进行预处理,把格式化后与格式化前的差值大于0的放在一个结构体里面,把小于0的放在一个结构体里。

先处理大于0的,对其根据b值进行升序排列,然后模拟过程(设一开始的剩余空间为0),用sum记录过程中出现的最小负值,再用ans记录剩余空间(就是待会儿程序里面的co)。

再处理小于0的,同上操作(不过这时候剩余空间不是0了,上面操作已经更改过了);

然后sum的绝对值就是我们想要的答案啦!具体证明明天我再问问stonepage;

具体代码如下

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdlib>
using namespace std;
typedef long long LL;
const int maxn = ;
struct SD{
LL a,d;
}p[maxn];
struct counter{
LL a,b,co;
}pluss[maxn],dece[maxn];
bool cmp1(counter a,counter b){
return a.b < b.b;
}
bool cmp2(counter a,counter b){
return a.a > b.a;
}
LL n,ans,sum,now1,now2;
LL get_num(){
LL num = ;
char c;
bool flag = false;
while((c = getchar()) == ' ' || c == '\n' || c == '\r');
if(c == '-')flag = true;
else num = c - '';
while(isdigit(c = getchar()))
num = num * + c - '';
return (flag ? - : ) * num;
}
void init(){
memset(p,,sizeof(p));
memset(pluss,,sizeof(pluss));
memset(dece,,sizeof(dece));
now1 = now2 = ;
}
int main(){
init();
n = get_num();
for(int i = ;i <= n;++i){
p[i].d = get_num();
p[i].a = get_num();
if(p[i].a >= p[i].d){
pluss[++now1].a = p[i].a;
pluss[now1].b = p[i].d;
pluss[now1].co = p[i].a - p[i].d;
}
else{
dece[++now2].a = p[i].a;
dece[now2].b = p[i].d;
dece[now2].co = p[i].a - p[i].d;
}
}
sort(pluss+,pluss+now1+,cmp1);
sort(dece+,dece+now2+,cmp2);
for(int i = ;i <= now1;++i){
sum = min(sum,ans - pluss[i].b);
ans += pluss[i].co;
}
for(int i = ;i <= now2;++i){
sum = min(sum,ans - dece[i].b);
ans += dece[i].co;
}
printf("%lld\n",abs(sum));
return ;
}

如果大家对我的博客有所意见,请通过我的邮箱联系我,谢谢。