【bzoj1465/bzoj1045】糖果传递 数论

题目描述

老师准备了一堆糖果, 恰好n个小朋友可以分到数目一样多的糖果. 老师要n个小朋友去拿糖果, 然后围着圆桌坐好, 第1个小朋友的左边是第n个小朋友, 其他第i个小朋友左边是第i-1个小朋友. 大家坐好后, 老师发现, 有些小朋友抢了很多的糖果, 有的小朋友只得到了一点点糖果, 甚至一颗也没有 , 设第i个小朋友有ai颗糖果. 小朋友们可以选择将一些糖果给他左边的或者右边的小朋友, 通过”糖果传递”最后使得每个小朋友得到的糖果数是一样多的, 假设一颗糖果从一个小朋友传给另一个小朋友的代价是1, 问怎样传递使得所耗的总代价最小.

输入

第一行一个正整数n,表示小朋友的个数. n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.

输出

输出只有一个数, 表示最小代价.

样例输入

4
1
2
5
4

样例输出

4


题解

数论?! Orz http://hzwer.com/2656.html

设第i个小朋友给第i-1个小朋友的糖果数为xi(第1个给第n个),

由于每个小朋友最后剩余的糖果数都是平均数ave,那么有:

a1-x1+x2=ave

a2-x2+x3=ave

……

an-xn+x1=ave

可以看出最后一个方程可以由前n-1个推出来,是多余的,于是怒删

将这里的前i个方程加起来,可以发现其中的变量只包含xi+1和x1,即xi+1=ave*i-∑aj (1≤j≤i),即xi=ave*(i-1)-∑aj (1≤j<i)

为了方便,令ci=∑(aj-ave) (1≤j≤i),就变成了xi=x1-c(i-1)。

所求为|x1|+|x2|+……+|xn|=|x1-0|+|x1-c1|+|x1-c2|+...+|x1-c(i-1)|

根据某定理,x1等于0、c1、c2、...、c(i-1)的中位数时所求最小。

然后加一遍就行了。

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
ll a[1000010] , c[1000010];
int main()
{
	int n , i;
	ll ave = 0 , ans = 0;
	scanf("%d" , &n);
	for(i = 1 ; i <= n ; i ++ )
		scanf("%lld" , &a[i]) , ave += a[i];
	ave /= n;
	for(i = 2 ; i <= n ; i ++ )
		c[i] = c[i - 1] + a[i] - ave;
	sort(c + 1 , c + n + 1);
	for(i = 1 ; i <= n ; i ++ )
		ans += abs(c[i] - c[(n + 1) >> 1]);
	printf("%lld\n" , ans);
	return 0;
}

 

posted @ 2017-03-14 18:51  GXZlegend  阅读(301)  评论(0编辑  收藏  举报