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 }
一道比较巧妙的贪心题目,感觉自己贪心这部分还很薄弱,也要补一补了...
独立意志与自由思想是必须争的,且须以生死力争。