[UVa 11300]Spreading the Wealth

题解

首先每个人最后的金币数是可以计算出来的,我们记其为$M$。
假设有$4$个人,编号$1$~$4$,第$i$个人初始金币数量为$A_i$,设$1->4$金币数为$x_1$(符号代表给出还是收入),那么我们对于标号为$1$的人很容易得到一个等式$M=A_1-x_1+x_2$。
对于所有人我们都可以得到这样的一个等式,一共有$n$个变量,但可惜我们发现其实有效的等式只有只有$n-1$个(因为任意$n-1$个等式都可以推出剩下的一个等式)。
我们无法求出答案,但我们可以试着用一个变量表示其他的变量,以$x_1$为例;
对于第一个人,$A_1-x_1+x_2=M => x_2=M-A_1+x_1=x_1-C_1$(令$C_1=A_1-M$)
对于第二个人,$A_2-x_2+x_3=M => x_3=M-A_2+x_2=2M-A_1-A_2+x_1=x_1-C_2$(令$C_2=C_1+A_2-M$)
……
对于第$n$个人,$A_n-x_n+x_1=M$,这个是多余的,舍去。
依题,我们要求$$sum_{i=1}^N Abs(x_i)$$
对于刚才的推导,就是$$sum_{i=1}^N Abs(x_1-C_i)$$
转化为数学模型就是数轴上所有点到一个点的距离。
那么原题就是找到一个点,使得所有点到其距离和最短,显然找到一个中间点即可。

 1 #include <map>
 2 #include <set>
 3 #include <cmath>
 4 #include <ctime>
 5 #include <queue>
 6 #include <stack>
 7 #include <cstdio>
 8 #include <string>
 9 #include <vector>
10 #include <cstdlib>
11 #include <cstring>
12 #include <iostream>
13 #include <algorithm>
14 #define LL long long
15 #define Max(a, b) ((a) > (b) ? (a) : (b))
16 #define Min(a, b) ((a) < (b) ? (a) : (b))
17 #define Abs(a) ((a) < 0 ? (-(a)) : (a))
18 using namespace std;
19 const int N = 1000000;
20 
21 LL n, m, ans;
22 LL c[N+5];
23 
24 void work() {
25     m = 0, c[1] = 0;
26     for (int i = 1; i <= n; i++)
27         scanf("%lld", &c[i+1]),
28         m += c[i+1];
29     m /= n;
30     for (int i = 1; i <= n; i++)
31         c[i] += c[i-1]-m;
32     sort(c+1, c+1+n);
33     LL x1 = c[(1+n)>>1];
34     ans = 0;
35     for (int i = 1;i <= n; i++)
36         ans += Abs(x1-c[i]);
37     printf("%lld
", ans);
38 }
39 
40 int main() {
41     while ((~scanf("%lld", &n)) && n) {
42         work();
43     }
44     return 0;
45 }
原文地址:https://www.cnblogs.com/NaVi-Awson/p/7520039.html