UVA11300分金币

题意:
      圆桌旁作者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\n" ,Ans);
   }
   return 0;
}
      
      
      
      
      
      
      
   
 





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值