Spreading the Wealth
圆桌旁坐着n个人,没人有一定数量的金币,金币总数能被n整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数目相等。你的任务是求出被转手的金币的最小值。比如,n=4,且4个人的金币数量分别是1,2,5,4时,只需转移4枚金币(第3个人给第2个人两枚金币,第2个人和第4个人分别给第1个人一枚金币)即可实现每人手中的金币数目相等。
【样例输入】
3
100
100
100
4
1
2
5
4
【样例输出】
0
4
令M为总金币的平均数,假设对于第i个人,原金币有A[i]个,他给前一个人x个金币,后一个人给他y个金币,则A[i]-x+y=M。
对于第1个人,A1-x1+x2=M → x2=x1-C1 (令C1=A1-M)
对于第2个人,A2-x2+x3=M →x3=M-A2+x2 → x3=x1-C2 (C2=C1+A2-M)
对于第3个人,同理的 x4=x1-C3 (C3=C2+A3-M)
我们希望所有的xi的绝对值之和最小,即|x1|+|x1-C1|+|x2-C2|+——+|x1-Cn-1|(即在数轴上找一点使得到各点Ci距离之和最小的点,这个点就是所有Ci的中位数(证明请参考刘汝佳的训练指南))
代码:
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=1000005;
long long A[maxn],point[maxn];
int main(){
int n;
while(scanf("%d",&n)!=EOF){
long long sum=0,M,x,ans=0;
for(int i=0;i<n;i++){
scanf("%lld",&A[i]);
sum+=A[i];
}
M=sum/n;
point[0]=0;
for(int i=1;i<n;i++)
point[i]=point[i-1]+A[i]-M;
sort(point,point+n);
x=point[n/2];
for(int i=0;i<n;i++)
ans+=abs(x-point[i]);
printf("%lld\n",ans);
}
return 0;
}