ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

糖果传递

2022-03-01 08:00:46  阅读:202  来源: 互联网

标签:right 传递 leq cdots overset 糖果 left


糖果传递

有 $n$ 个小朋友坐成一圈,每人有 $a \left[ i \right]$ 个糖果。

每人只能给左右两人传递糖果。

每人每次传递一个糖果代价为 $1$。

求使所有人获得均等糖果的最小代价。

输入格式

第一行输入一个正整数 $n$,表示小朋友的个数。

接下来 $n$ 行,每行一个整数 $a \left[ i \right],表示第 $i$ 个小朋友初始得到的糖果的颗数。

输出格式

输出一个整数,表示最小代价。

数据范围

$1 \leq n \leq 1000000$,
$0 \leq a \left[ i \right] \leq 2 \times 10^{9}$,

数据保证一定有解。

输入样例:

4
1
2
5
4

输出样例:

4

 

解题思路

  很难想到这是一道数学题。

  设$x_{i}$为第$i$个人给前一个人($i - 1$。其中当$i = 1$时,前一个人为第$n$个人)的糖果数量。注意,这里的$x_{i}$可以是正数或者负数。当$x_{i}$为正数,表示第$i$个人给前一个人糖果;当$x_{i}$为负数,表示前一个人给第$i$个人糖果。

  因此整一个代价为$\left| x_{1} \right| + \left| x_{2} \right| + \cdots + \left| x_{n} \right|$,我们的目标就是求$\left| x_{1} \right| + \left| x_{2} \right| + \cdots + \left| x_{n} \right|$的最小值。

  设$\overset{-}{a}$为所有糖果的平均数,最后每个人手上的糖果数量应该为$\overset{-}{a}$,列方程:

\begin{cases}
a_{1} - x_{1} + x_{2} &= \overset{-}{a} \\
a_{2} - x_{2} + x_{3} &= \overset{-}{a} \\
&\vdots \\
a_{n - 1} - x_{n - 1} + x_{n} &= \overset{-}{a} \\
a_{n} - x_{n} + x_{1} &= \overset{-}{a} \\
\end{cases}

  发现秩不为$n$,方程有无穷多解。所有式子加起来会得到常数等于常数,即有$n - 1$个独立的方程,$n$个未知数。所以存在一个自由元,可以用某一个$x_{i}$来表示其他所有的$x$。

  移项,把上述方程变为

\begin{cases}
x_{1} - x_{2} &= a_{1} - \overset{-}{a} \\
x_{2} - x_{3} &= a_{2} - \overset{-}{a} \\
&\vdots \\
x_{n - 1} - x_{n} &= a_{n - 1} - \overset{-}{a} \\
x_{n} - x_{1} &= a_{n} - \overset{-}{a} \\
\end{cases}

从最后一个方程开始,每次都往前加上一个方程,得到

\begin{cases}
x_{1} &= x_{1} - 0 \\
x_{2} &= x_{1} - \left( {\left( {n - 1} \right) \cdot \overset{-}{a} - a_{2} - a_{3} - \cdots - a_{n}} \right) \\
&\vdots \\
x_{n - 1} &= x_{1} - \left( {2 \cdot \overset{-}{a} - a_{n - 1} - a_{n}} \right) \\
x_{n} &= x_{1} - \left( {\overset{-}{a} - a_{n}} \right) \\
\end{cases}

这样我们就可以用$x_{1}$来表示其他所有的$x$了。

  代入$\left| x_{1} \right| + \left| x_{2} \right| + \cdots + \left| x_{n} \right|$中,有$$\left| {x_{1} - 0} \right| + \left| {x_{1} - \left( {\left( {n - 1} \right) \cdot \overset{-}{a} - a_{2} - a_{3} - \cdots - a_{n}} \right)} \right| + \cdots + \left| {x_{1} - \left( {\overset{-}{a} - a_{n}} \right)} \right|$$对于上面中的每一项,我们可以发现$x_{1}$都是减去一个常数,因此可以写成$$\left| {x_{1} - c_{1}} \right| + \left| {x_{2} - c_{2}} \right| + \cdots + \left| {x_{n} - c_{n}} \right|$$

  我们可以惊奇的发现,要求上式的最小值,等价于要找到一个$x_{1}$,使得$x_{1}$分别到$c_{1} \sim c_{n}$的距离的和最小。

  当$x_{1}$取到$c_{1} \sim c_{n}$的中位数时,上式就可以取到最小值。这个模型可以参考货仓选址这一题。这里简单证明一下。

  先假定$c_{1} \leq c_{2} \leq \cdots \leq c_{n}$。

  我们把式子$$\left| {x_{1} - c_{1}} \right| + \left| {x_{2} - c_{2}} \right| + \cdots + \left| {x_{n} - c_{n}} \right|$$的每一项分成若干组,第$1$项和第$n$项为一组,第$2$项和第$n - 1$项为一组,以此类推,如果$n$为奇数,那么第$\left\lceil \frac{n}{2} \right\rceil$项就独自为一组,得到$$\left( {\left| {x_{1} - c_{1}} \right| + \left| {x_{1} - c_{n}} \right|} \right) + \left( {\left| {x_{1} - c_{2}} \right| + \left| {x_{1} - c_{n - 1}} \right|} \right) + \cdots$$由绝对值不等式$\left| {\left| a \right| - \left| b \right|} \right| \leq \left| {a - b} \right| \leq \left| a \right| + \left| b \right|$,得到$$\left| {x_{1} - c_{1}} \right| + \left| {x_{1} - c_{n}} \right| \geq \left| {x_{1} - c_{1} - \left( {x_{1} - c_{n}} \right)} \right| = \left| {c_{n} - c_{1}} \right|$$意味着当$x_{1} \in \left\lbrack {c_{1}, ~c_{n}} \right\rbrack$,才取到等号。对于式子的其他组,同理可得。最后式子变为$$\left( {\left| {x_{1} - c_{1}} \right| + \left| {x_{1} - c_{n}} \right|} \right) + \left( {\left| {x_{1} - c_{2}} \right| + \left| {x_{1} - c_{n - 1}} \right|} \right) + \cdots \geq \left| {c_{n} - c_{1}} \right| + \left| {c_{n - 1} - c_{2}} \right| + \cdots$$我们可以发现,当每一组都取到等号,上式才可以取到最小值。因为我们一开始规定了$c_{1} \leq c_{2} \leq \cdots \leq c_{n}$,因此可以发现要给每一组都取到等号,$x_{1}$的取值区间都在不断缩小,要一直到最后一组都要满足。可以发现就是取$c_{1} \sim c_{n}$的中位数(如果$n$为奇数,中位数就是$c_{\left\lceil \frac{n}{2} \right\rceil}$,偶数的话,取$c_{\frac{n}{2}}$或$c_{\frac{n}{2} + 1}$都可以)。

  当然,我们还可以从几何意义去考虑,可以发现只有当$x_{1}$在$c_{1} \sim c_{n}$这个区间内,$x_{1}$到$c_{1}$与$c_{n}$的距离之和才会最小,其他组也是这样分析,最后得到的结论相同。

  最后我们来看看$c_{i}$是怎么求的。

  看回上面的方程组,可以发现$c_{n} = {\overset{-}{a} - a_{n}}$,$c_{n - 1} = 2\overset{-}{a} - a_{n - 1} - a_{n} = c_{n} - \overset{-}{a} - a_{n - 1}$,......,$c_{1} = c_{2} - \overset{-}{a} - a_{1} = 0$。

可以发现递推式$c_{i} = c_{i + 1} - \overset{-}{a} - a_{i}$。

  AC代码如下:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int N = 1e6 + 10;
 6 
 7 int a[N];
 8 long long c[N];
 9 
10 int main() {
11     int n;
12     scanf("%d", &n);
13     
14     long long sum = 0;
15     for (int i = 1; i <= n; i++) {
16         scanf("%d", a + i);
17         sum += a[i];
18     }
19     
20     int avg = sum / n;
21     
22     // 通过递推式求ci
23     for (int i = n; i; i--) {
24         c[i] = c[i + 1] - avg + a[i];
25     }
26     
27     sort(c + 1, c + n + 1); // 排序,使得ci是递增的顺序。由于ci的位置不会影响答案,因此使得ci为递增的序列,方便求中位数
28     
29     long long ret = 0;
30     for (int i = 1; i <= n + 1 >> 1; i++) {
31         ret += c[n - i + 1] - c[i]; // 最小值就是每个点到中位数的距离的和,也就是每组区间的长度的和
32     }
33     printf("%lld", ret);
34     
35     return 0;
36 }

 

参考资料

  AcWing 122. 糖果传递(蓝桥杯C++ AB组辅导课):https://www.acwing.com/video/723/

标签:right,传递,leq,cdots,overset,糖果,left
来源: https://www.cnblogs.com/onlyblues/p/15947208.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有