bzoj 1555: KD之死 (贪心+STL)

18 篇文章 0 订阅

1555: KD之死

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 99   Solved: 47
[ Submit][ Status][ Discuss]

Description

在F出去旅游的这几十年里面,地球上已经发生了翻天覆地的变化。原来KD早知道不和谐的地球即将会爆发有史以来的第一次SC(S**t Combat)大战,这场战争有可能毁灭地球,所以才强行推荐F去火星家园,以躲避这次战争。 战争发生的这些年间,KD带领的正义清扫军顽强抵抗,与敌人势均力敌,才让摇摇欲坠的地球得到残存。可惜世事难料,KD终是被奸人所害,让敌人从后方攻进基地,应对不及,身受重伤,奄奄一息。(日薄西山,气息奄奄。人命危浅,朝不虑夕。。。。。) SM(S**t Mother):哇嘎嘎嘎嘎嘎,天的光芒在照耀着我,你死定啦,地球就要毁灭啦。 但是SM没有发现,那个光芒是由F的拖拉机突破大气层时因摩擦产生火焰而发出的。在地球引力的加速下,拖拉机在X米高空处将F弹出后,碰巧飞速撞在了SM的身上。。。。。。SM惨叫一声后,就戏剧性的消逝了。虽然KD眼疾翅快,找了一个屏障,但毕竟是伤痕累累,受不住这么大的冲击,因此也圆寂了。。。。。。。。。 轰隆。。。KD和其他阵亡战士的躯体被装进了重重的GC里面,准备送往墓地。由于战争导致的科技极度退化,大家回到了板车时代。所以不得不将这些GC一个个竖着叠堆起来放在板车上,并由SD拖走。每个盒子都有一个重量W和它所能承受的最大重量T,即最多能有T单位重的盒子堆在它上面,否则会把它压烂,显然这个是不包括自身重量的。拖车虽然很顽强坚固,但是毕竟还是拖车,所以也还是有最大承受重量的。 因为和S混战了N久的SD也没多少力气了,所以他不想多次来回拖灵车,因此他只好每次拖运都装上尽量多的盒子。而且,还有更另SD抓狂的事:因为有些战士清扫功绩辉煌,所以必须在第一次拖运就将装他们的GC送往墓地。由于智商无限,SD想了半天都没想出来,无奈之下只好求助于过去世界的你,希望你告诉他第一次最多可以装多少个GC。

Input

第一行3个正整数N、M和MAXV,表示一共有N个GC,其中有M个GC必须在第一次运到墓地,拖车的最大承受重量是MAXV。 接下来N行每行2个正整数W和T,表示这个GC自身重量是W个单位,最大承受量是T个单位。 接下来M行每行一个正整数P,表示第P个输入的GC第一次必须运到墓地。

Output

一个正整数ANS,表示在满足要求的情况下,第一次最多能运多少GC到墓地。如果无法满足要求,请输出“Foolish SD!”。

Sample Input

2 0 6
4 2
2 3

Sample Output

2

HINT

对于10%的数据,N<=10;
对于40%的数据,N<=100,W、T<=10000;
对于100%的数据,N<=600000,W、T<=2000000000;
注意事项:
数据很弱。

Source

[ Submit][ Status][ Discuss]

题解:贪心+STL

考虑相邻两个的影响:如果at-bw>bt-aw,那么b放到a上比a放到b上更优。

因为b放到a上剩余的承重量更大。

那么我们可以按照at+aw从小到大排序,然后把车看成必选元素加入到最后。

我们现在插入的顺序是从上到下的放置顺序,即每次加入的放在最底层。然后将必选和不必选的分开考虑。

我们用一个大根堆维护目前加入的不必选的元素,这些元素是有可能被弹出的。

如果当前是必选元素,当前加入的所有元素的和超过了当前元素的承重量,那么我们就将堆中元素依次弹出,只到当前元素可以加入为止,如果堆空了还是无法加入,那么就无解

如果当前是不必选元素,能加入就直接加入,扔到大根堆中。如果加入不了就比较堆顶元素与当前元素w的大小,如果当前元素较小,并且只要弹出堆顶元素就可以加入,就将堆顶元素弹出,把当前元素加入。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#define N 1000003
#define LL long long 
using namespace std;
int n,m,ans; 
LL sum,tot;
priority_queue<LL> p;
struct data{
	LL w,t; bool flag;
	bool operator <(const data &a) const{
		return w+t<a.w+a.t;
	}
}a[N];
int main()
{
	freopen("a.in","r",stdin);
	scanf("%d%d%lld",&n,&m,&tot);
	for (int i=1;i<=n;i++) scanf("%lld%lld",&a[i].w,&a[i].t);
	for (int i=1;i<=m;i++) {
		int x; scanf("%d",&x);
		a[x].flag=1;
	}
	sort(a+1,a+n+1); 
	a[++n].w=0; a[n].t=tot; a[n].flag=1;
	bool pd=true;
	for (int i=1;i<=n;i++) {
		if (a[i].flag) {
			while (sum>a[i].t) {
				if (p.empty()) {
				  pd=false; break;
				}
				sum-=p.top(); p.pop(); ans--;
			}
			if (!pd) break;
			sum+=a[i].w; ans++;
		}
	    else {
	    	if (!p.empty()&&sum>a[i].t)
	    	 if (p.top()<a[i].w||sum-p.top()>a[i].t) continue;
	    	if (!p.empty()&&sum>a[i].t) sum-=p.top(),p.pop(),ans--;
			p.push(a[i].w); sum+=a[i].w; ans++;
		}
	}
	if (!pd) printf("Foolish SD!");
	else printf("%d\n",ans-1);
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值