noip2018模拟题(类背包+贪心)
- 马拉松冰球赛
(marathon.pas/c/cpp)
马拉松冰球锦标赛的日子就要到了。正如马拉松冰球比赛中经常出现的那样,比赛时间是 M 分钟。和常规的冰球比赛一样,在每一给定时刻,场上两队各有 6 名球员。然而,一场马拉松冰球比赛可以持续很长时间,所以教练带了一群球员,这样当球员们累了的时候, 他们可以进行替换。
其中一个名为 Ante 的教练是我们故事的主角。Ante 带了 N 个球员参加比赛。对于每一个球员,他知道两个参数:球员的能力值 K 和耐力值 I。耐力值是指球员参赛的最大总时间。假设一个球员先参加 X 分钟,然后休息,再参加 Y 分钟,他的总参赛时间就是 X+Y。当一个球员的总参赛时间等于其耐力值的时候,他就会感到疲惫,不能继续参赛,所以这个时候, 就需要其他人来代替他,否则他会晕倒在赛场上,最终被送进医院(马拉松冰球是一个危险的项目)。
在一个给定时刻,队伍的能力值就是当前参赛队员能力值的总和。Ante 并不是一个伟大的教练,所以他要求你拿出最初的六名球员和替补球员的方案,以便他能达到每个时刻队 伍能力值总和的可能的最大值 Z。保证一定能找到一种方案,使得每个时刻场上都有 6 名球员。
举个例子,假设比赛时间为 3 分钟,而第一分钟队伍的能力值是 15,第二分钟队伍的能力值是 12,第三分钟队伍的能力值是 14,Z 就等于 15+12+14=41。
请注意:在马拉松冰球赛中是没有守门员的,因为比赛必须有趣。
【输入】
第一行输入两个正整数 M 和 N(1≤M≤500 000,6≤N≤500000),分别表示比赛的持续时间(以分钟为单位),和 Ante 带领的球员数量。
接下来 N 行,每行两个正整数 K 和 I(1≤K≤100 000,1≤I≤M),表示每个球员的能力值和耐力值。
球员按照输入顺序,从 1 到 N 编号。
【输出】
第一行包含题目要求的可能的最大值 Z。
【输入输出样例】
200 6 |
6600 |
3 200 |
|
4 200 |
|
5 200 |
|
6 200 |
|
7 200 |
|
8 200 |
|
9 9 |
1260 |
10 3 |
|
9 3 |
|
13 9 |
|
5 3 |
|
15 9 |
|
100 9 |
|
3 6 |
|
2 6 |
|
1 6 |
|
3 9 |
1610 |
100 3 |
|
100 3 |
|
100 3 |
|
100 3 |
|
100 2 |
|
100 1 |
|
50 1 |
|
30 2 |
|
1 1 |
|
这道题虽然是一道比较水的题目
但是也然我认识到一些比较重要的东西
如背包能求出最优值,而一些贪心则会导致算法错误
比如这道题,若直接贪心,那么就会导致一些值大的运动员无法得到足够时间发挥,
但是用背包思想处理的话,就不会产生此类情况,因为用容量减,就不会出现一些选手得不到全部时间发挥
背包会自我调控到能替代的运动员后面替换之
所以以后遇到类似题目,一定学会转换思想,换成背包试试
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int maxn=500000+10; struct my{ ll k,I; }; my a[maxn]; bool cmp(const my &x,const my &y){ return x.k>y.k; } int main(){ ll n,m; ll ans=0; scanf("%lld%lld",&m,&n); for (int i=1;i<=n;i++){ scanf("%lld%lld",&a[i].k,&a[i].I); } int p=0; sort(a+1,a+1+n,cmp); m*=6; for (int i=1;i<=n;i++){ if(m-a[i].I>=0){ m-=a[i].I; ans+=(a[i].k*a[i].I); } else if(m>0) { m=0; ans+=(m*a[i].k);break; } } printf("%lld",ans); return 0; }