题意:
圆桌旁作者n个人,每个人都有一定数量的金币,他们每次可以给相邻的人一枚金币(可以给多次),问所有人金币数都相同的话最少要给多少次金币。
思路:
这个题目感觉很好,首先我们可以假设每个人都向他前面的人给出了xi的金币,x1表示1这个人给了n这个人(因为是环)多少金币,x2表示2给了以多少金币,xi可以使负数,负数说明是反着给的x2=-4说明是一给了二4枚金币,这样我们就可以列出来一些方程组了
,假设M是平均数,Ai表示第i个人的金币数,那么有
A1-x1+x2=M -> x2=x1-(A1-M)= x1-C1 设C1=A1-M
A2-x2+x3=M ->x3 = x2-(A2-M)=x1-C1-(A2-M)= x1-C2 设C2=(A1-M)+(A2-M)
同理 x3= x1-C3 设C3= (A1-M)+(A2-M)+(A3-M)
我们用含有A1的式子推出x2,用含有A2的退出x3...所以我们没有必要用最后一个式子,还有一点就是 x1 = x1 - C0 那么C0=0;
这样推到之后就变成我们是要求 |x1| + |x1-C1| + |x2-C2|......
那么把他们和一维坐标联系起来,是不是就是求所有点到x1点(Ci构成的点)的距离和的最小值了,这样我们只要求出x1就行了,其实这个x1就是所有C的中位数,为什么是这样这个很好理解,我们可以在纸上画一画,比如当前的x1左边有4个点,右边有5个点,那么把x1向右移动一小块距离d(不要跨过右边的点)我们会发现整体是左边增加4d,右边减少5d所以我们要往左移,不能往右移,最后奇数的情况就是中间的那个数最优(中位数),偶数的时候是中间的那两个之间的位置(包括中间的那两个)的区间都是最优的,还可以用中位数表示。
#include<stdio.h>
#include<algorithm>
#define N 1000000 + 10
using namespace std;
long long num[N];
long long C[N];
long long abss(long long x)
{
return x > 0 ? x : -x;
}
int main ()
{
int n ,i;
long long Ans ,Sum ,M;
while(~scanf("%d" ,&n))
{
for(Sum = 0 ,i = 1 ;i <= n ;i ++)
{
scanf("%lld" ,&num[i]);
Sum += num[i];
}
M = Sum / n;
C[0] = 0;
for(i = 1 ;i < n ;i ++)
C[i] = C[i-1] + num[i] - M;
sort(C ,C + n);
long long x1 = C[n/2];
for(Ans = 0 ,i = 0 ;i < n ;i ++)
Ans += abss(x1 - C[i]);
printf("%lld
" ,Ans);
}
return 0;
}