標籤:
題目串連請戳此處
題意: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