codeforces 671B
来源:互联网 发布:神武手游多开软件 编辑:程序博客网 时间:2024/06/09 21:03
We all know the impressive story of Robin Hood. Robin Hood uses his archery skills and his wits to steal the money from rich, and return it to the poor.
There are n citizens in Kekoland, each person hasci coins. Each day, Robin Hood will take exactly1 coin from the richest person in the city and he will give it to the poorest person (poorest person right after taking richest's1 coin). In case the choice is not unique, he will select one among them at random. Sadly, Robin Hood is old and want to retire ink days. He decided to spend these last days with helping poor people.
After taking his money are taken by Robin Hood richest person may become poorest person as well, and it might even happen that Robin Hood will give his money back. For example if all people have same number of coins, then next day they will have same number of coins too.
Your task is to find the difference between richest and poorest persons wealth afterk days. Note that the choosing at random among richest and poorest doesn't affect the answer.
The first line of the input contains two integers n andk (1 ≤ n ≤ 500 000, 0 ≤ k ≤ 109) — the number of citizens in Kekoland and the number of days left till Robin Hood's retirement.
The second line contains n integers, thei-th of them isci (1 ≤ ci ≤ 109) — initial wealth of thei-th person.
Print a single line containing the difference between richest and poorest peoples wealth.
4 11 1 4 2
2
3 12 2 2
0
Lets look at how wealth changes through day in the first sample.
- [1, 1, 4, 2]
- [2, 1, 3, 2] or [1, 2, 3, 2]
So the answer is 3 - 1 = 2
In second sample wealth will remain the same for each person.
题意: 有n个人,每次操作使最富有的人的金钱数-1,然后让最穷的人的钱数+1(如果最富有的人的钱数不等于最穷的人的话),问你经过k次操作之后,最富有的人和最穷的人金钱差多少?
分析:这道题从O(n * k)优化到O(k * log n)特别简单,对最大值和最小值进行操作,红黑树嘛,可以用多重集合来做multset,不过!肯定没那么容易让你过,下面是直接模拟超时的代码:
/************************************************************************* > File Name: tmp.cpp > Author: Triose > Mail: Triose@163.com > Created Time: 2016年06月04日 星期六 21时47分32秒 ************************************************************************/#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<map>#include<set>using namespace std;//#define ONLINE_JUDGE#define eps 1e-8#define INF 0x7fffffff#define inf 0x3f3f3f3f#define rep(i,a) for(int(i)=0; i<(a);(i)++)#define mem(a,b) (memset((a),b,sizeof(a)))#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)#define sfs(a) scanf("%s",a)#define pf(a) printf("%d\n",a)#define pfd(a,b) printf("%d %d\n",a,b)#define pfs(a) printf("%s\n",a)#define pfI(a) printf("%I64d\n",a)#define enter putchar(10)#define LL __int64const double PI = acos(-1.0);const double E = exp(1.0);template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }template<class T> inline T Min(T a, T b) { return a<b ? a : b; }template<class T> inline T Max(T a, T b) { return a>b ? a : b; }int n, m;multiset<int> ms;multiset<int>::iterator low, high;int main() {#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);//freopen("Out.txt", "w", stdout);#endifint tmp;while(~sfd(n,m)) {ms.clear();rep(i, n) {sf(tmp);ms.insert(tmp);}while(m--) {low = ms.begin();high = ms.end();high--;if((*low) != (*high)) {ms.insert((*low) + 1);ms.insert((*high) - 1);ms.erase(low);ms.erase(high);}}low = ms.begin(); high = ms.end(); high--;pf(*high - *low);}return 0;}
亲测超时,二分n不行, 那就二分k吧。我们假设!(这种方法很常用)
首先,每一次操作使最大的-1,最小的+1。如果操作次数足够多的话,最小值和最大值都会趋近于sum / n 对不对?那么区间就出来了
最小值可能出现的区间:Min(a[i]) ~ sum / n
最大值可能出现的区间:Max(a[i]) ~ (sum % n == 0 ? sum / n : sum / n + 1)
好,我们把操作分成增加最小和减少最大两个部分来看,也就是分别求出终态的最大值和最小值
假设!终态的最大值为m, 那么所有比m大的数都要进行a[i] - m次操作, 累加这些得到一个count。
如果count 小于k, 那么这个最大值m太大了,让high等于m - 1,用变量ans记录下可取的最大值 ans = m。
如果count 等于k, 那么正好,此时的m就是答案,直接return m就行。
如果count 大于k, 那么这个最大值m太小了, 让low 等于m + 1。
重复以上操作,最后return ans即可。
同理可求出最小值。
最大值和最小值做差即可得出答案。
这个假设的办法太好了!想了好久没想出来!!
/************************************************************************* > File Name: 671B.cpp > Author: Triose > Mail: Triose@163.com > Created Time: 2016年06月02日 星期四 09时32分29秒 ************************************************************************/#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<map>#include<set>using namespace std;//#define ONLINE_JUDGE#define eps 1e-8#define INF 0x7fffffff#define inf 0x3f3f3f3f#define rep(i,a) for(int (i)=0; i<(a);(i)++)#define mem(a,b) (memset((a),b,sizeof(a)))#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)#define sfs(a) scanf("%s",a)#define pf(a) printf("%d\n",a)#define pfd(a,b) printf("%d %d\n",a,b)#define pfs(a) printf("%s\n",a)#define pfI(a) printf("%I64d\n",a)#define enter putchar(10)#define LL long longconst double PI = acos(-1.0);const double E = exp(1.0);template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }template<class T> inline T Min(T a, T b) { return a<b ? a : b; }template<class T> inline T Max(T a, T b) { return a>b ? a : b; }template<class T> T Abss(T a, T b) { return a - b > 0 ? a - b : b - a;}int n, m;#define N 500010int a[N];int maxx, minn;LL sum;int get_max() { int low = (sum % n == 0 ? sum / n : sum / n + 1), high = maxx; int mid;LL count; int ans = 0; while(low <= high) {mid = (low + high) >> 1;count = 0;rep(i, n) count += Max(0, a[i] - mid);if(count <= m) { ans = mid; high = mid - 1;}else { low = mid + 1;} } return ans;}int get_min() { int low = minn, high = sum / n; int mid;LL count; int ans = 0; while(low <= high) {mid = (low + high) >> 1;count = 0;rep(i, n) count += Max(0, mid - a[i]);/*cout << "high:" << high << endl;cout << "mid:" << mid << endl;cout << "low:" << low << endl;*/if(count <= m) { ans = mid; low = mid + 1;}else { high = mid - 1;} }// cout << "ans = " << ans << endl; return ans;}int main() {#ifndef ONLINE_JUDGE freopen("in.txt","r",stdin);// freopen("Out.txt", "w", stdout);#endif while(~sfd(n,m)) {maxx = -1;minn = INF;sum = 0;rep(i, n) { sf(a[i]); sum += a[i]; maxx = Max(maxx, a[i]); minn = Min(minn, a[i]);}/*cout << sum << endl;cout << "max:" << get_max() << endl;cout << "min:" << get_min() << endl;*/pf(get_max() - get_min()); } return 0;}
- codeforces 671B
- codeforces 671B
- Codeforces 671B 二分
- CodeForces 671B Robin Hood
- codeforces B
- codeforces B
- codeforces B
- codeforces B
- Codeforces 671B Robin Hood 二分答案
- Codeforces 671B Robin Hood 【思维】
- 【模拟】Codeforces 671B Robin Hood
- Codeforces 671B Robin Hood (二分搜索)
- CodeForces 671 B.Robin Hood(水~)
- CodeForces 626B CodeForces 626B【暴力】
- CodeForces 841B (B) 博弈
- codeforces 134B
- codeforces#98 b
- codeforces 105 div2 B
- jquery学习总结(超级详细)
- java huffman树的构造和huffman编码
- UITextView的使用
- 火星人
- Camera API1 从应用到CameraService分析
- codeforces 671B
- 黑马程序员视频笔记---保存文件到SD卡
- C 对于C语言可移植性的思考
- 6.4学习记录
- Centos7 搭建Redis3.2.0版本集群环境
- Leetcode 86. Partition List 链表划分 解题报告
- 关于DNF金刚Go游戏的决策实践
- java 实现二叉树的构建,先序,中序,后序,层次,递归,非递归的遍历
- 98. Validate Binary Search Tree