UVa 11300 Spreading the Wealth 数学题

题目大意:有n 个人围坐在一个圆桌旁,每个人手中有一定数量的金币,金币的总数能够被n整除,现在每个人可以给自己旁边的两个人传递金币,要使得每个人手中的金币数相同,问最少要经过多少次的传递,假设每次只能给一个金币。

解题报告:感觉这题就是一道纯粹的数学题,代数思想很重要。我们可以假设x2是第二个人给第一个人的金币的数量,注意这里若x2是整数,表示第二个人给第一个人金币,若x2是负数,则表示第一个人给第二个人金币,同理x3表示第三个人给第二个人的金币数量,由于桌子是圆的,所以x1就表示第1个人给第n个的金币数量。假设第i个人他一开始手上有Ai个金币,他给了i-1个人xi个金币,然后i+1个人又给了他x(i+1)个金币,所以他现在手上的金币数是Ai-xi+x(i+1),又因为最后要达到所有人手上的金币数相同,所以假设最后每个人手上有M个金币,M=总的金币数/n,所以就有方程Ai-xi+x(i+1)=M,就有

x2=x1-(A1-M)

x3=x1-(A1+A2-2*M);

........

所以最后一共要传递的次数就等于x1+x2+x3+......xn,即|x1-(A1-M)|,   |x1-(A1+A2-2*M)|....,而这个又可以看成是在一条数轴上的一个点到n-1个点的距离之和,和明显就是中位数了,所以求出中位数就可以求出所有的和了。这题要注意的是数据量会比较大,要用long long。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 
 7 const int MAXS=1000000+5;
 8 
 9 long long C[ MAXS ] , X[ MAXS ] ; 
10 int main ( ) {
11     long long n,M;
12     while(scanf("%lld",&n)!=EOF) {
13         long long  d,x1,sum;
14         C[0]=0;
15         for(int i=1;i<=n;++i) {
16             scanf("%lld",&d);
17             C[i]=C[i-1]+d;
18         }
19         M=C[n]/n;
20         for( int i=1;i<n;++i)
21         C[i]-=i*M;
22         std::sort(C+1,C+n);
23         if(n&1)
24         x1=(C[(n-1)/2]+C[(n-1)/2+1])/2;
25         else x1=C[n/2];
26         sum=abs(x1);
27         for(int i=1;i<n;++i)
28         sum+=abs(x1-C[i]);
29         printf("%lld\n",sum);
30     }
31     return 0;
32 }
View Code

 

posted @ 2013-06-03 20:15  xiaxiaosheng  阅读(173)  评论(0编辑  收藏  举报