Description
有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。
Input
第一行一个正整数n<=987654321,表示小朋友的个数.接下来n行,每行一个整数ai,表示第i个小朋友得到的
糖果的颗数.
Output
求使所有人获得均等糖果的最小代价。
Sample Input
4
1
2
5
4
Sample Output
4
解题方法: 设i顺时针传给下一个人的数量为xi,目标平均值值为ave。则目标就是让ai−xi+x(i-1)−1=ave的前提下最小化。
可以构造出
a1−x1+x2=ave
a2−x2+x3=ave
a1−x3+x4=ave
…..
an−xn+x1=ave
这个方程组有n个方程和n个变量,但显然,最后一个方程式无意义。
于是考虑:
a1−x1+x2=ave⟹x2=ave+x1−a1
a2−x2+x3=ave⟹x3=ave+x2−a2=2×ave−a1−a2+x1
a3−x3+x4=ave⟹x4=3×ave−a1−a2−a3+x1
…
记c[i]=(sigma(a[j]),j从到i)-i*ave
所以:
x2=x1-c1
x3=x1-c2
….
我们希望Xi的绝对值之和尽量小,即|x1| + |x1-c1| + |x1-c2| + ……+ |x1-c(n-1)|要尽量小。注意到|x1-ci|的几何意义是数轴上的点x1到xi的距离,所以问题变成了:给定数轴上的n个点,找出一个到他们的距离之和尽量小的点,而这个点就是这些数中的中位数,证明略。上面的c是直接替换之后的结果,也是下面代码里面的c,画一下就明白了。(0,c1,c2,c3”’,c[n-1])的中位数。
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
int a[N], c[N];
int n;
int main(){
scanf("%d", &n);
long long ave = 0;
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
ave += a[i];
}
ave /= n;
for(int i = 2; i <= n; i++){
c[i] = c[i-1] + a[i] - ave;
}
sort(c + 1, c + n + 1);
long long ans = 0;
int j = (n + 1) / 2;
for(int i = 1; i <= n; i++){
ans += abs(c[i] - c[j]);
}
printf("%lld\n", ans);
return 0;
}