题意: n n n个人,每个人有 A i A_i Ai颗糖果,第 i i i人给第 i − 1 i-1 i−1人 X i X_i Xi颗糖果(第一人给第 n n n人, X i X_i Xi可正可负,负数表示第 i − 1 i-1 i−1个给第i人),设平均值为 a v e ave ave,每给一颗糖果记为一次操作,问最少操作次数使n个人的糖果数量最少。
~
~
参考大佬博客F_J
主要证明(复述):
a
v
e
=
A
1
+
X
2
−
X
1
ave = A_1 + X_2 - X_1
ave=A1+X2−X1
a
v
e
=
A
2
+
X
3
−
X
2
ave = A_2 + X_3 - X_2
ave=A2+X3−X2
……
a
v
e
=
A
n
+
X
1
−
X
n
ave = A_n+ X_1 - X_n
ave=An+X1−Xn
=
=
>
==>
==>
X
2
=
X
1
−
(
A
1
−
a
v
e
)
X_2 = X_1-(A_1-ave)
X2=X1−(A1−ave)
X
3
=
X
1
−
(
A
1
+
A
2
−
a
v
e
∗
2
)
X_3 = X_1-(A_1+A_2-ave*2)
X3=X1−(A1+A2−ave∗2)
……
X
n
=
X
1
−
(
A
1
+
A
2
.
.
.
.
.
.
A
n
−
a
v
e
∗
(
n
−
1
)
)
X_n = X_1-(A_1+A_2......A_n-ave*(n-1))
Xn=X1−(A1+A2......An−ave∗(n−1))
令
S
i
=
∑
i
=
1
n
A
[
i
]
−
a
v
e
S_i = \sum_{i=1}^{n}{A[i]-ave}
Si=∑i=1nA[i]−ave
=
=
>
==>
==>
X
2
=
X
1
−
S
1
X_2 = X_1-S_1
X2=X1−S1
X
3
=
X
1
−
S
2
X_3 = X_1-S_2
X3=X1−S2
……
X
n
=
X
1
−
S
n
X_n = X_1-S_n
Xn=X1−Sn
操作次数就是:
a n s = ∑ i = 1 n X i = ∑ i = 1 n ∣ X 1 − S i ∣ ans = \sum_{i=1}^nX_i = \sum_{i=1}^{n} \mid X_1-S_i\mid ans=∑i=1nXi=∑i=1n∣X1−Si∣
那么原问题变成了求 X1 的值使得上述求和最小,上述求和可以看作是求点到直线的距离。
先将 S 数组从小到大排序。
如果 n 为奇数,那么 X1=Sn/2+1
如果 n 为偶数,那么 X1∈[Sn/2,Sn/2+1]
可以发现,不论 n 为奇数还是偶数,X1 都可以取到S 数组中的某个值使得求和最小,因此存在某个 Xi=X1−Si=0,即有两个人之间没有纸牌传递,因此这种解法实际上证明了环形均分纸牌问题的可链化。
结论:
我们取数组
b
[
i
]
=
A
i
−
a
v
e
b[i]=A_i-ave
b[i]=Ai−ave的前缀和数组
s
u
m
[
i
]
sum[i]
sum[i]的中值为
X
1
X_1
X1,求出最小操作次数。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
typedef long long ll;
ll s[N], sum[N];
int main() {
ll n, ave = 0;
cin >> n;
for(int i=1; i<=n; i++) {
cin >> s[i]; ave += s[i];
}
ave /= n;
for(int i=1; i<=n; i++) {
s[i] -= ave; sum[i] = sum[i-1] + s[i];
}
sort(sum+1, sum+1+n);
ll mid = (1+n)/2, ans = 0;
for(int i=1; i<=n; i++) {
ans += abs(sum[mid] - sum[i]);
}
cout << ans;
return 0;
}