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 }