一、题目链接
AcWing 122. 糖果传递
进阶题目 AcWing 105. 七夕祭
二、题目分析
(一)算法标签
贪心 排序 中位数 推公式
(二)解题思路
设 x i x_i xi为i号小朋友(初始有 a i a_i ai个糖果)向i-1号小朋友传递的糖果数(其中,i=2,3,4,…,n, 若 x i x_i xi为负数,则表示i-1号小朋友向i号小朋友传递的糖果数),特别地当i=1时, x 1 x_1 x1表示1号小朋友向n号小朋友传递的糖果数
目标:
∣
x
1
∣
+
∣
x
2
∣
+
∣
x
3
∣
+
⋯
+
∣
x
n
−
1
∣
+
∣
x
n
∣
\vert x_1 \vert + \vert x_2\vert+\vert x_3 \vert+ \dots +\vert x_{n-1} \vert+\vert x_n \vert
∣x1∣+∣x2∣+∣x3∣+⋯+∣xn−1∣+∣xn∣最小
由题意,可得:
{
x
1
=
x
2
+
a
1
−
a
ˉ
x
2
=
x
3
+
a
2
−
a
ˉ
⋯
x
n
−
1
=
x
n
+
a
n
−
1
−
a
ˉ
x
n
=
x
1
+
a
n
−
a
ˉ
\begin{cases} x_1=x_2+a_1-\bar a \\ x_2=x_3+a_2-\bar a \\ \cdots \\ x_{n-1}=x_n+a_{n-1}-\bar a \\ x_n=x_1+a_n-\bar a \\ \end{cases}
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧x1=x2+a1−aˉx2=x3+a2−aˉ⋯xn−1=xn+an−1−aˉxn=x1+an−aˉ
n个方程相加得到一个恒等式: 0 = a 1 + a 2 + ⋯ + a n − n a ˉ 0=a_1+a_2+\cdots+a_n-n\bar a 0=a1+a2+⋯+an−naˉ,所以上面的方程组有n-1个有效方程,n个未知元,那么可以用其中一个未知元来表示其它n-1个未知元
对上述方程组作一下变换,可以得到:
{
x
1
=
x
1
−
0
x
2
=
x
3
−
[
(
n
−
1
)
a
ˉ
−
a
n
−
a
n
−
1
−
⋯
−
a
2
]
⋯
x
n
−
1
=
x
1
−
(
2
a
ˉ
−
a
n
−
a
n
−
1
)
x
n
=
x
1
−
(
a
ˉ
−
a
n
)
\begin{cases} x_1=x_1-0 \\ x_2=x_3-[(n-1)\bar a - a_n-a_{n-1}-\cdots-a_2]\\ \cdots \\ x_{n-1}=x_1-(2\bar a-a_n-a_{n-1}) \\ x_n=x_1-(\bar a - a_n) \\ \end{cases}
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧x1=x1−0x2=x3−[(n−1)aˉ−an−an−1−⋯−a2]⋯xn−1=x1−(2aˉ−an−an−1)xn=x1−(aˉ−an)
等价于下面方程组:
{
x
1
=
x
1
−
c
1
x
2
=
x
3
−
c
2
⋯
x
n
−
1
=
x
1
−
(
2
a
ˉ
−
a
n
−
a
n
−
1
)
x
n
=
x
1
−
(
a
ˉ
−
a
n
)
\begin{cases} x_1=x_1-c_1 \\ x_2=x_3-c_2\\ \cdots \\ x_{n-1}=x_1-(2\bar a-a_n-a_{n-1}) \\ x_n=x_1-(\bar a - a_n) \\ \end{cases}
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧x1=x1−c1x2=x3−c2⋯xn−1=x1−(2aˉ−an−an−1)xn=x1−(aˉ−an)
其中,
{
c
1
=
0
c
2
=
(
n
−
1
)
a
ˉ
−
a
n
−
a
n
−
1
−
⋯
−
a
2
⋯
c
n
−
1
=
2
a
ˉ
−
a
n
−
a
n
−
1
c
n
=
a
ˉ
−
a
n
\begin{cases} c_1=0 \\ c_2=(n-1)\bar a - a_n-a_{n-1}-\cdots-a_2 \\ \cdots \\ c_{n-1}=2\bar a-a_n-a_{n-1}\\ c_n=\bar a - a_n\\ \end{cases}
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧c1=0c2=(n−1)aˉ−an−an−1−⋯−a2⋯cn−1=2aˉ−an−an−1cn=aˉ−an
可以发现当
i
>
1
i>1
i>1时
c
i
=
c
i
+
1
+
a
ˉ
−
a
i
c_i=c_{i+1}+\bar a -a_i
ci=ci+1+aˉ−ai
回到目标:
此时,
∣
x
1
∣
+
∣
x
2
∣
+
∣
x
3
∣
+
⋯
+
∣
x
n
−
1
∣
+
∣
x
n
∣
\vert x_1 \vert + \vert x_2\vert+\vert x_3 \vert+ \dots +\vert x_{n-1} \vert+\vert x_n \vert
∣x1∣+∣x2∣+∣x3∣+⋯+∣xn−1∣+∣xn∣最小
等价于
∣
x
1
−
c
1
∣
+
∣
x
1
−
c
2
∣
+
∣
x
1
−
c
3
∣
+
⋯
+
∣
x
1
−
c
n
−
1
∣
+
∣
x
1
−
c
n
∣
\vert x_1-c_1 \vert + \vert x_1-c_2\vert+\vert x_1-c_3 \vert+ \dots +\vert x_1-c_{n-1} \vert+\vert x_1-c_n \vert
∣x1−c1∣+∣x1−c2∣+∣x1−c3∣+⋯+∣x1−cn−1∣+∣x1−cn∣最小 (其中
c
1
,
c
2
,
⋯
,
c
n
c_1,c_2,\cdots,c_n
c1,c2,⋯,cn 均为常数)
当
x
1
x_1
x1取
c
1
,
c
2
,
⋯
,
c
n
c_1,c_2,\cdots,c_n
c1,c2,⋯,cn的中位数即可使上述式子的值最小
此时,问题转换成了AcWing 104. 货仓选址【贪心】【《算法竞赛进阶指南》】
三、AC代码
解法一:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
int a[N], c[N];
int n;
int main()
{
cin >> n;
LL sum = 0;
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &a[i]);
sum += a[i];
}
// 每个小朋友最后的糖果数一样,所以平均数一定是整数
LL avg = sum / n;
// 求c[i]
for (int i = n; i > 1; i -- )
c[i] = c[i + 1] + avg - a[i];
// 找c[i]的中位数
sort(c + 1, c + 1 + n);
LL mid = c[1 + n >> 1];
// 求结果
LL res = 0;
for (int i = 1; i <= n; i ++ )
res += abs(c[i] - mid);
cout << res << endl;
return 0;
}