【题解】AT_abc313_c 题解

AT_abc313_c 题解

思路分析

简单推柿子的题。

我们要如何使得这个数列的最大值与最小值的差为 11 呢?显然是要尽可能的去让数列中的数平均分布。

显然,当两个数一个加 11,一个减 11 时,两数和不变。又因为每次都是这样的操作,因此操作完毕后数列总和不变。

设数列总和为 SS,数列中有 nn 个数。则尽可能平均时,情况如下:

  • SmodnS \bmod n 个数为 Sn\left\lceil\\\dfrac{S}{n}\right\rceil
  • 余下的前面的数为 Sn\left\lfloor\\\dfrac{S}{n}\right\rfloor

然后,我们求出操作次数。

设两数原为 aia_ibib_i,要变为 pip_iqiq_ibiaib_i \le a_ipiqip_i \ge q_i)。由题意,ai+bi=pi+qia_i+b_i = p_i + q_i,即 piai=biqip_i - a_i = b_ i - q_i

piai=biqi=kp_i - a_i = b_ i - q_i = k

由于两者要变化的量 kk 相同,因此,只需操作 kk 次即可。如何计算 kk 呢?由 kk 的定义,2k=piai+biqi2k=p_i-a_i+b_i-q_i,即 k=biai+piqi2k = \dfrac{b_i-a_i+p_i-q_i}{2}k=aibi+piqi2k = \dfrac{\left|a_i-b_i\right|+\left|p_i-q_i\right|}{2}

还有,由于我们要满足条件 biaib_i \le a_i,因此要对数列排序。而 piqip_i \ge q_i 是天然满足的,因此不用排序。

最后,由于该情况是最平均的情况,所以操作至此情况所需的步骤也最小。因此按照上述步骤实现即可。

代码

#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define int long long
#define IL inline
using namespace std;
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;

IL int read()
{
    int x = 0,f = 1;
    char c = getchar();
    while(c <'0'|| c >'9'){if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar();
    return x * f;
}

void write(int x)
{
    if(x < 0) putchar('-'),x = -x;
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

int a[N], b[N];

signed main()
{
	int n;
	cin >> n;
	int s = 0; //和 
	for(int i = 1;i <= n;i++)
	{
		cin >> a[i];
		s += a[i];
	}	
	sort(a + 1, a + n + 1); 
	for(int i = 1;i <= n - s % n;i++) //余下的前面的数为 floor(s/n) 
	{
		b[i] = s / n; 
	}
	for(int i = 1;i <= s % n;i++) //后 s % n 个数为 ceil(s/n)(即floor(s / n) + 1) 
	{
		b[n - i + 1] = s / n + 1;
	}
	//依照公式计算操作次数 
	int ans = 0;
	for(int i = 1;i <= n;i++)
	{
		ans += abs(b[i] - a[i]);
	}
	cout << ans / 2 << endl;
    return 0;
}
posted @ 2023-08-07 10:44  邻补角-SSA  阅读(15)  评论(0)    收藏  举报  来源