Codeforces Round #352 (Div. 2) D. Robin Hood
Posted fukan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #352 (Div. 2) D. Robin Hood相关的知识,希望对你有一定的参考价值。
题意:n个人每人有一定的财富值ci,每天Robin Hood从最富的人手中取财富1分给最穷的人(取后最穷,
即可以退回),若有多个最穷的人,任选一个给出财富值。问k天后最富的人和最穷的人财富差值为多少。
1 ≤ n ≤ 500 000, 0 ≤ k ≤ 109
1 ≤ ci ≤ 109
分析:
每一天随着财富值的取和给,最穷的人和最富的人都在动态更新。
最后要求的是 (richest-poorest)min,那么 要使这个等式最小,只需求出k天后richest的最小值和poorest
最大值即可。由于富人的财富是单调递减的,穷人的财富是单调递增的。那么二分枚举就可以找到这两个值。
枚举的左右端点 保守点选择L=1,R=1e9。这样复杂度大概是log2(109)约为log2(230)=30。
当poorest(max)<richest(min),ans = richest(min) - poorest(max);
否则,即出现了穷人变富人,富人变穷人,说明中间肯定有某天d<k使得财富值相等或者相差1。
这时ans = sum%n==0?0:1。
需要注意是中间过程 可能会爆int,最好全用longlong
1e9表示109。这个e表示小数点移动几位。
C中的常量,后缀缺省时,整数的类型为int,浮点数的类型为double。
所以使用时,若常量需要为long long ,则应该在后面加LL后缀。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> using namespace std; typedef long long ll; ll c[500005],sum,n; ll cal1(ll x) { ll sum = 0; for(int i=0;i<n;i++) { if(c[i]>x) sum += (c[i]-x); } return sum; } ll cal2(ll x) { ll sum = 0; for(int i=0;i<n;i++) { if(c[i]<x) sum += (x-c[i]); } return sum; } int main() { ll k; while(~scanf("%I64d%I64d",&n,&k)) { sum = 0; for(int i=0;i<n;i++) { scanf("%I64d",&c[i]); sum += c[i]; } sort(c,c+n); ll l = 1,r = 1e9; ll rich,poor,mid; while(l<r) { mid = l+(r-l)/2; if(cal1(mid)<=k) { rich = mid; r = mid; } else l = mid+1; } l = 1,r = 1e9; while(l<r) { mid = l+(r-l)/2; if(cal2(mid)<=k) { poor = mid; l = mid+1; } else r = mid; } if(poor<rich) printf("%I64d\n",rich-poor); else printf("%d\n",sum%n == 0?0:1); } return 0; }
以上是关于Codeforces Round #352 (Div. 2) D. Robin Hood的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #352 (Div. 2) D. Robin Hood
Codeforces Round #436 E. Fire(背包dp+输出路径)
[ACM]Codeforces Round #534 (Div. 2)
Codeforces Round #726 (Div. 2) B. Bad Boy(贪心)