UVA 11300 Spreading the Wealth

来源:互联网 发布:qt4.8 json封装和解析 编辑:程序博客网 时间:2024/06/05 06:01

题目来源

Description

圆桌旁坐着 n 个人, 每人有一定数量的金币, 金币总数能被 n 整除。 每个人可以给他左右相邻的人一些金币, 最终使得每个人的金币数目相等。 你的任务是求出被转手的金币数量的最小值。 比如 n=4, 且 4 个人的金币数量分别为 1,2,5,4 时, 只需转移 4 枚金币(第 3 个人给第 2 个人两枚金币, 第 2 个人和第 4 个人分别给第 1 个人 1 枚金币)即可实现每人手中的金币数目相等。

Input

输入包含多组数据。 每组数据第一行为整数 n (n <= 1 000 000), 以下 n 行每行为一个整数, 按逆时针顺序给出每个人拥有的金币数。 输入结束标志为文件结束符(EOF)。

Output

对于每组数据, 输出被转出的金币数量的最小值。 输入保证这个值在 64 位无符号整数范围内。

SampleInput

310010010041254

SampleOutput

04

Analyze

设现在每个人的财产为A1, A2, A3, ..., An, 最后均分的钱M = sum(Ai)/n.

Xi表示 第 i 号给第 i-1 号的金币数量,Xi < 0, 则第 i-1 号 给 第 i 号的金币。

那么:

对于第一个人: A1-X1+X2 = M => X2 = X1 - (A1 - M)对于第二个人: A2-X2+X3 = M => X3 = X2 - A2 + M = X1 - (A1 + A2 - 2M)对于第三个人: A3-X3+X4 = M => X4 = X3 - A3 + M = X1 - (A1 + A2 + A3 - 3M)...对于第 n 个人: An-Xn+X1 = M我们要求的是所有 Xi 的绝对值之和 S 最小。即:s = |X1| + |X2| + |X3| +... 要小。我们可以看到 |Xi| = |X1 - 一个已知的值|, 那么它所表示的几何意义就是数轴上点 X1 到  这个已知的值Ci 的距离。所以问题变成了: 给定数轴上的 n 个点, 请找出一个点 使得这个点到这 n 个点的距离和最小。这个点就是这些数的中位数。

证明:

画一个数轴图,然后任意找一个点移动, 然后求距离和,可以发现:

  • n 为奇数时: 中间的那个点,距离和是最短的。
  • n 为偶数时, 中间的那两个点的平均值那个位置,距离和是最短的。

Code

#include <cstdio>#include <algorithm>#include <iostream>#include <cstring>#include <fstream>#include <map>#include <queue>#include <set>#include <cstdlib>#include <ctime>#include <vector>#include <cmath>#include <limits.h>using namespace std;const int maxn = 1000001 + 10;long long A[maxn], C[maxn];int main(){    int n;    while(scanf("%d", &n) == 1)    {        long long sum = 0;        for(int i=0; i<n; i++)        {            scanf("%lu", &A[i]);            sum += A[i];        }        sum = sum / n;        C[0] = 0;        for(int i=1; i<n; i++)        {            C[i] = C[i-1] + A[i] - sum;        }        sort(C, C+n);        long long X1 = C[n/2], ans=0;        for(int i=0; i<n; i++)  ans += abs(X1 - C[i]);        printf("%lld\n", ans);    }    return 0;}
原创粉丝点击