codeforces 671B

来源:互联网 发布:神武手游多开软件 编辑:程序博客网 时间:2024/06/09 21:03
B. Robin Hood
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

Input

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.

Output

Print a single line containing the difference between richest and poorest peoples wealth.

Examples
Input
4 11 1 4 2
Output
2
Input
3 12 2 2
Output
0
Note

Lets look at how wealth changes through day in the first sample.

  1. [1, 1, 4, 2]
  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;}



0 0