首页 > 技术文章 > 信息学奥赛一本通 高手训练1 游戏通关

acioi 2019-09-21 07:27 原文

游戏通关

【题目描述】

XY在玩一个包含N个任务的游戏。每个任务完成时限为Ti(你可以认为还没开始做任务时的时间为0),奖励为Wi。由于XY技术的娴熟以及任务的简单,对于每个任务,他都可以在一个单位时间内完成。

XY想要知道他能够获得的最多的奖励。

【输入】

第一行一个整数N,表示需要完成的任务数目。

接下来N行,每行两个整数T、W,分别表示完成这个任务的最后期限和完成这个任务后获得的奖励。

【输出】

输出数据有且仅有一行,只包含一个整数,表示最多获得的奖励。

【输入样例】

2
1 5
1 4

【输出样例】

5

【样例输入2】

5
2 3
1 2
4 5
1 3
3 4

【样例输出2】

15

【样例解释2】

对于样例2,XY可以选择完成任务1、3、4和5,这样他可以获得奖励15。

【数据规模及约定】

对于10%的数据,N≤100,Ti≤100,Wi≤2000。
对于30%的数据,N≤1000,Ti≤5000,Wi≤2000。
对于50%的数据,N≤10000,Ti≤20000,Wi≤2000。
对于100%的数据,N≤200000,Ti≤200000,Wi≤2000。

【思路】

贪心 + 大根堆的题目,感jio一本通就喜欢贪心 + 大根堆的题目瞎说的
比较好想的贪心题目
因为这个在每一个单位时间内都可以得到一个奖励
所以只需要将每个单位时间内能够得到的最高的奖励累加起来就好了
不过一个单位时间内的最高奖励不只有自己这个单位时间之前完成的那些任务
还有在这个单位时间之后完成的任务
可以这样想,任务1在a时间之前完成
那么就可以在时间为a-1的时候去完成任务1
依次类推下去a - 2,a - 3……都是可以去完成任务1的
所以每一个单位时间x可以得到的最高奖励是x+1到最晚的那个时间点的所有任务里面奖励值最大的那个
这样就可以想到倒着枚举,放入大根队中,加上队首就好了

【易错易漏】

容易在贪心求某个点a能够得到的最高奖励的时候,只求在这个点之前要求完成的任务,也就是只有那些要求在时间a之前完成的任务(不包括前面的也不包括后面的),这个时候纠错掉了我就是在这里错掉的

【完整代码】

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>

using namespace std;
const int Max = 200005;
struct node
{
	int t,v;
}a[Max];
priority_queue<int>q;
bool cmp(const node x,const node y)
{
	return x.t > y.t;
}
int n;
int main()
{
	int ttt = 0;
	scanf("%d",&n);
	for(int i = 1;i <= n;++ i)
		scanf("%d%d",&a[i].t,&a[i].v),ttt = max(a[i].t,ttt);
	sort(a + 1,a + 1 + n,cmp);
	int ans = 0;
	int js = 0;
	for(int i = ttt;i >= 1;i --)
	{
		while(a[++ js].t >= i)q.push(a[js].v);
		js --;
		if(!q.empty())
		{
			ans += q.top();
			q.pop();
		}
	}
	cout << ans << endl;
	return 0;
}

推荐阅读