UVa Spreading the Wealth-11300(数学推导+中位数)

Spreading the Wealth

Problem

A Communist regime is trying to redistribute wealth in a village. They have have decided to sit everyone around a circular table. First, everyone has converted all of their properties to coins of equal value, such that the total number of coins is divisible by the number of people in the village. Finally, each person gives a number of coins to the person on his right and a number coins to the person on his left, such that in the end, everyone has the same number of coins. Given the number of coins of each person, compute the minimum number of coins that must be transferred using this method so that everyone has the same number of coins.

The Input

There is a number of inputs. Each input begins with n(n<1000001), the number of people in the village. n lines follow, giving the number of coins of each person in the village, in counterclockwise order around the table. The total number of coins will fit inside an unsigned 64 bit integer.

The Output

For each input, output the minimum number of coins that must be transferred on a single line.

Sample Input

3
100
100
100
4
1
2
5
4

Sample Output

0
4



//思路:

 分析:首先最终每个人的金币数量可以计算出来,它等于金币总数除以人数n。接下来用M来表示每个人最终拥有的金币数。

  现在假设编号为 i 的人初始有A枚金币,对于1号来说,他给了4号x1枚金币,还剩A-x1枚金币;但是2号给了他x2枚金币,所以还剩A1-x1+x2枚金币。所以A1-x1+x2=M。同理对于第2个人,有A2-x2+x3=M。最终得到n个方程,实际上只有n-1个有用。

  尝试用x1表示出其他的x,则本题就变成了单变量的极值问题。

  对于第1个人,A1-x1+x2=M x2=M-A1+x1=x1-C1(规定C1=A1-M,下面类似)

  对于第2个人,A2-x2+x3=M x3=M-A2+x2=2M-A1-A2+x1=x1-C2

  对于第3个人,A3-x3+x4=M x4=M-A3+x3=3M-A1-A2-A3+x1=x1-C3

  ...

  对于第n个人,An-xn+x1=M。这是一个多余的等式。

  我们希望所有xi 的绝对值之和尽量小,即|x1|+|x1-C1|+|x1-C2|+...+|x1-Cn-1|要最小。注意到|x1-Ci|的几何意义是数轴上的点x1到C的距离,所以问题变成了:给定数轴上n个点,找出一个到他们距离之和尽量小的点。

  而这个点就是中位数,它实在是太优美,太巧妙了,而且不少其他问题也能用的上,接下来要证明它。

  在有6个点的数轴上,任取一点,比如最左边和最右边点的中点K,它的左边有4个点,右边有2个点。把它往左移一点,不要移太多,以免碰到输入点。假设移动的d单位距离,则这个点K左边4个点到它的距离各减少了d,右边的2个点到它的距离各增加了d,但总的来说,距离之和减少了2d。如果K的左边有2个点,右边有4个点,道理类似,不过应该向右移动。

  换句话说,只要灰点左右的输入点不一样多,就不是最优解。所以,如果输入点一共有奇数个,则灰点必须和中间的那个点重合(中位数);如果有偶数个,则灰点可以位于最中间两个点之间的任意位置(还是中位数)。


AC源码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

typedef long long LL;
const int maxn=1000000+10;

LL A[maxn],c[maxn],n;
int main()
{
	while(~scanf("%lld",&n))
	{
		LL tot=0;
		for(int i=1;i<=n;++i)	{scanf("%lld",&A[i]);tot+=A[i];}
		LL M=tot/n;
		c[0]=0;
		for(int i=1;i<n;++i)	{c[i]=c[i-1]+A[i]-M;}
		sort(c,c+n);
		LL ans=0,x1=c[n/2];
		for(int i=0;i<n;++i)	{ans+=abs(x1-c[i]);}
		printf("%lld\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值