[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\n", ans); 38 } 39 40 int main() { 41 while ((~scanf("%lld", &n)) && n) { 42 work(); 43 } 44 return 0; 45 }
博主蒟蒻,随意转载。但必须附上原文链接:http://www.cnblogs.com/NaVi-Awson/,否则你会终生找不到妹子!!!