智力大冲浪(洛谷P1230)
题目描述
小伟报名参加中央电视台的智力大冲浪节目。本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元。先不要太高兴!因为这些钱还不一定都是你的?!接下来主持人宣布了比赛规则:
首先,比赛时间分为n个时段(n≤500),它又给出了很多小游戏,每个小游戏都必须在规定期限ti前完成(1≤ti≤n)。如果一个游戏没能在规定期限前完成,则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的。当然,每个游戏本身都很简单,保证每个参赛者都能在一个时段内完成,而且都必须从整时段开始。主持人只是想考考每个参赛者如何安排组织自己做游戏的顺序。作为参赛者,小伟很想赢得冠军,当然更想赢取最多的钱!注意:比赛绝对不会让参赛者赔钱!
输入输出格式
输入格式:
输入文件riddle.in,共4行。
第1行为m,表示一开始奖励给每位参赛者的钱;
第2行为n,表示有n个小游戏;
第3行有n个数,分别表示游戏1到n的规定完成期限;
第4行有n个数,分别表示游戏1到n不能在规定期限前完成的扣款数。
输出格式:
输出文件riddle.out,仅1行。表示小伟能赢取最多的钱。
输入输出样例
输入样例:
10000 7 4 2 4 3 1 4 6 70 60 50 40 30 20 10
输出样例:
surf
9950
注:完成第一、二、三、四、六个任务得到最多钱。
这是一道贪心题,我们可以对于每个时段,保证扣得钱数最少。
对于样例,我们分别对游戏编号:
①. 4 70
②. 2 60
③. 4 50
④. 3 40
⑤. 1 30
⑥. 4 20
⑦. 6 10
其中第一列为编号,第二列为规定期限ti,第三列为未完成的赔钱。
显然,对于第一个时段,我们最优解是完成第五个游戏,这样赔钱数为0,已完成游戏⑤。
对于第二个时间段,我们最优解是完成第二个游戏,这样赔钱数还是为0,已完成游戏⑤②。
对于第三个时间段同理已完成⑤②④。
对于第四个时间段,游戏①我们肯定是要选的,因为它赔钱数最多,剩下的③⑥加起来会赔70元,但在这里,我们注意到,我们已完成的游戏里面⑤的赔钱数是30,但③的赔钱数是50,如果我们完成③放弃⑤,赔钱数只是50比之前优,而这个③我们就可以放在第一个时间段去完成
剩下的⑥所赔的钱都比已完成的少,就也放弃了。
第五个时间段,我们就只能完成⑦了。
在第四个时间段里,我们之所以能交换已完成的游戏和待完成的游戏是因为我们是根据规定期限从小到大排序的,这样后来完成的游戏肯定能在先前完成。
并且对于每个时段我们都保证了当前赔钱数最低,所以到了最后赔钱数也自然最低。
所以我们就把已完成的游戏的最小赔钱数和这个时段必须完成的最大赔钱数比较,如果小于则交换即可。
我们要用堆来维护已完成游戏的最小赔钱数,并对游戏按照期限进行排序。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 priority_queue<int> qwq; //已完成游戏的堆 8 int n,len; 9 long long m; 10 struct data{ 11 int t,w; //t为期限,w为赔钱数 12 }game[505]; 13 bool comp(const struct data &a,const struct data &b){ 14 if (a.t<b.t) return 1; 15 if (a.t>b.t) return 0; 16 if (a.t==b.t) return (a.w>b.w); 17 } 18 void work(int x){ 19 qwq.push(-game[len].w); //负号即转化为小根堆 20 len++; 21 if (x<game[len].t) return; //这个游戏不是这个时段必须完成的话就退出 22 while (game[len].t==x){ 23 int a=-qwq.top(); //开始比较已完成游戏最小赔钱数与要完成的游戏的赔钱数 24 if (a<game[len].w){ 25 qwq.pop(); 26 qwq.push(-game[len].w); 27 len++; 28 } 29 else {len++;return;} 30 } 31 return; 32 } 33 int main(){ 34 cin>>m>>n; 35 long long all=0; 36 for (int i=1;i<=n;i++) 37 cin>>game[i].t; 38 for (int i=1;i<=n;i++){ 39 cin>>game[i].w; 40 all+=game[i].w; 41 } 42 len=1; 43 sort(game+1,game+1+n,comp); 44 for (int i=1;i<=n;i++) 45 work(i); 46 long long ans=0; 47 while (qwq.size()){ 48 ans+=-qwq.top(); //ans为已完成的赔钱数 49 qwq.pop(); 50 } 51 cout<<m-(all-ans)<<endl; 52 return 0; 53 }