这是 liangbob 用来存放一些自己写的傻逼东西的地|

园龄:粉丝:关注:

【题解】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;
}

本文作者:邻补角の杂货铺

本文链接:https://www.cnblogs.com/sslbj/p/18708396

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   邻补角-SSA  阅读(4)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开