AcWing
122. 糖果传递
假设小朋友的编号从$1$到$n$,$x_i$表示小朋友$i$传递给小朋友$i+1$的糖果数量,特殊地,$x_n$表示小朋友$n$传递给小朋友$1$的糖果数量。数组$a[N]$表示小朋友原先有的糖果数量,$aver$表示每个小朋友糖果数量的平均值。那么有:
$ans = min{\lvert x_1 \rvert + \lvert x_2 \rvert + \cdots + \lvert x_n \rvert}$
$aver = a_1 - x_1 + x_n$,即$x_1 = x_n - (aver - a_1)$
$aver = a_2 - x_2 + x_1 = x_n + (a_1 + a_2 - 2aver)$,即$x_2 = x_n - (2aver - a_1 - a_2)$
$\cdots$
$x_{n-1} = x_n - ((n-1)aver - a_1 - a_2 - \cdots - a_{n-1})$
$x_n = x_n - 0$
那么$ans = min{\lvert x_1 \rvert + \lvert x_2 \rvert + \cdots + \lvert x_n \rvert} = min{\lvert x_n - s_1 \rvert + \lvert x_n - s_2 \rvert + \cdots + \lvert x_n - s_n \rvert}$.
即,在数轴上寻找一个点,使得其到点{$s_1$, $s_2$, $\cdots$, $s_n$}的距离之和最小,只需要找到这些点在数轴上的中位数,即为$x_n$,再求距离之和。
#include <bits/stdc++.h>
using namespace std;
int n;
const int N = 1000010;
int a[N];
typedef long long LL;
LL s[N];
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n;
LL sum = 0;
for(int i = 1; i <= n; i ++){
cin >> a[i];
sum += a[i];
}
int aver = sum / n;
LL res = 0, tmp = 0; // a[i]向a[i + 1]传递的糖果
for(int i = 1; i <= n; i ++) s[i] = s[i - 1] + aver - a[i];
sort(s + 1, s + n + 1);
int mid = (n + 1) / 2;
LL v = s[mid];
for(int i = 1; i <= n; i ++) res += abs(v - s[i]);
cout << res;
return 0;
}