Codeforce 1201C 二分
原题链接:http://codeforces.com/contest/1201/problem/C
题意:给出n个数(n为奇数),每一次操作可以将任意一个数加一,给出操作数,求这组数的中位数最大是多少。
思路:枚举中位数。数组由小到大排序后,从第n/2+1到第最后一个(因为是找最大中位数,所以数组前一半可以不管),遍历每一个数与当前中位数的差,将这些差作和,就是达到当前中位数所需要的操作次数,找到符合条件的最大中位数(条件即为操作次数小于规定次数)。
细节:
bool check(ll mid){ ll s=0; for(int i=n/2;i<n;i++){ if(a[i]<mid) s+=mid-a[i]; } return s<=k; }
当前中位数所需的操作数和,返回是否满足小于规定的操作数。
ll l=0,r=3e9; while(l<r){ ll mid=(l+r+1)/2; if(check(mid)){ l=mid; } else{ r=mid-1; } }
1.若满足小于规定操作数,则将当前中位数赋给l,下一次增加l的大小到mid看是否符合条件,如此往复;若不符合,退让一步,将mid-1赋给r,下一次得到更小的mid,同上往复。可以理解成大步向前,小步退后,因为找的是可能的最大值。
2.r的初始值要保证大于所有的结果,题中k最大1e9,a[i]最大也是1e9,操作是加一,所以加起来即可,再随便往大写一点(2e9也可以A)。
3.mid=(l+r+1)/2,因为int除法是向下取整,所以式子和mid=(l+r)/2+1是一样的。
完整代码:
#include <iostream> #include <algorithm> using namespace std; #define N 200010 typedef long long ll; ll a[N],n,k; bool check(ll mid){ ll s=0; for(int i=n/2;i<n;i++){ if(a[i]<mid) s+=mid-a[i]; } return s<=k; } int main(int argc, char** argv) { scanf("%lld%lld",&n,&k); for(int i=0;i<n;i++){ scanf("%lld",&a[i]); } sort(a,a+n); ll l=0,r=3e9; while(l<r){ ll mid=(l+r+1)/2; if(check(mid)){ l=mid; } else{ r=mid-1; } } printf("%lld\n",l); return 0; }

浙公网安备 33010602011771号