CF767E ChangeFree【贪心/优先队列】By cellur925

题目传送门

$naive$想法

最开始的一个贪心策略是每次尽量花掉硬币 ,如果不满足条件,就花纸币。而且不满足条件的时候,要尽量向百取整。(显然是不对的,因为有时候不够)但是显然这个贪心策略是错误的,因为花纸币的那一天可能恰好$Angry cashier$的愤怒值最高。那么我们怎么确认在哪天选择找钱?这是一个问题......


 

正解

首先我们知道,我们要把每天需要花的钱膜100来处理。我们不停地使用硬币,直到硬币数量变成负数,这告诉我们需要在这之前有一天换出了额外的硬币。

为了保证我们问题的贪心性,我们维护一个优先队列。队列里存的是每天$wi*(100-xi%100)$的值,也就是我们需要找钱的数量。

因为我们是到硬币数量为负数时才尽量去找之前要找钱的时刻,所以我们之前减的时候可以认为是无脑减的,而需要找钱的时候,我们恰好就使硬币数量增加100了。

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<queue>
 4 
 5 using namespace std;
 6 typedef long long ll;
 7 
 8 int n,m;
 9 ll ans;
10 int ned[100090],satis[100090],ex[100090];
11 struct cellur{
12     int id,w;
13 };
14 bool operator < (const cellur &x,const cellur &y)
15 {
16     return x.w>y.w;
17 }
18 priority_queue<cellur>q;
19 
20 int main()
21 {
22     scanf("%d%d",&n,&m);
23     for(int i=1;i<=n;i++)
24         scanf("%d",&ned[i]);
25     for(int i=1;i<=n;i++)
26         scanf("%d",&satis[i]);
27     for(int i=1;i<=n;i++)
28     {
29         int tmp=ned[i];
30         tmp%=100;
31         if(!tmp) continue;
32         cellur x;
33         x.id=i;
34         x.w=satis[i]*(100-tmp);
35         q.push(x);
36         m-=tmp;
37         if(m<0)
38         {
39             m+=100;
40             cellur u=q.top();q.pop();
41             ans+=u.w;
42             ex[u.id]++; 
43         }
44     }
45     printf("%lld\n",ans);
46     for(int i=1;i<=n;i++)
47     {
48         printf("%d ",ned[i]/100+ex[i]);
49         if(!ex[i]) printf("%d",ned[i]%100);
50         else printf("0");
51         printf("\n");
52     }
53     return 0;
54 } 
View Code

一道比较巧妙的贪心题目,感觉自己贪心这部分还很薄弱,也要补一补了...

posted @ 2018-10-12 21:43  cellur925&Chemist  阅读(253)  评论(0编辑  收藏  举报