http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2275
F. 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. nlines 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个人,每个人有一定数量的金币,金币总数能被n整除。每个人可以给他的左右相邻的人分一些金币,最终使得每个人的金币数量相等。求出被转手的金币数量的最小值。
分析:用M表示每人最终拥有的金币数。假设有4个人,编号1,2,3,4,。假设1号给2号3枚金币,2号又给1号5枚金币,实际等价于2号给1号2枚金币,而1号什么也没给2号。这样可以设x2表示2号给了1号多少枚金币。如果x2<0,说明1号给了2号-x2枚金币。x1,x3,x4含义类似。注意,由于是环形,x1指1号给4号多少金币。
先假设编号为i的人最初由A[i]枚金币。对1号来说,他给了4号x1枚金币,又从2号获得了x2枚金币,最后剩下A[1]-x1+x2。根据假设,A[1]-x1+x2=M.
同理,对第二个人,由A[2]-x2+x3=M。
因此,对于第一个人:A[1]-x1+x2=M → x2=x1-C[1](规定C[1] = A[1]-M)
对于第二个人: A[2]-x2+x3=M → x3=x2-(A[2]-M)=x1-C[1]-(A[2]-M) = x1-C[2] (C[2] = C[1]+A[2]-M,以下类似)
······
我们希望所有xi的绝对值之和尽量小,即|x1|+|x1-C[1]|+|x1-C[2]|+······+|x1-C[n-1]|要最小,注意到|x1-C[i]|的几何意义是数轴上点x1到C[i]的距离。所以问题就变成了:给定数轴上的n个点,找出一个到它们距离之和尽量最小的点。
这个最优的距离x1就是这些数的“中位数”(即排序后位于中间的数),因此只要做个排序即可。证明请在网上搜索。
代码如下:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; #define maxn 1000010 int n; long long a[maxn], sum, c[maxn]; int main() { while(~scanf("%d", &n)) { sum = 0; for(int i = 1; i <= n; i++) { scanf("%lld", &a[i]); sum += a[i]; } long long m = sum/n; c[0] = 0; for(int i = 1; i < n; i++) c[i] = c[i-1]+a[i]-m; sort(c, c+n); long long x1 = c[n/2]; long long ans = 0; for(int i = 0; i < n; i++) ans += abs(x1-c[i]); printf("%lld ", ans); } return 0; }