CJOJ P2295 【HAOI2008】糖果传递

来源:互联网 发布:文艺句子 知乎 编辑:程序博客网 时间:2024/05/10 11:42

题目大意:

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

思路:

求出平均数ave,设第i个小朋友的初始糖果数量为Ai,需要给第i-1位的小朋友xi个糖(xi<0则表示第i-1个小朋友给了第i个小朋友xi个糖,总之就是这两个人之间搞事情),
由此我们可以推得:
若要第1个小朋友的糖果数变为ave,则有ave=A1-x1+x2 进而推得 x2=x1-(A1-ave);
第2个小朋友:ave=A2-x2+x3 进而推得 x3=ave-A2+x2  -> x3=x1-(A1+A2-2*ave);
用x1-()的形式是有用意的;
.
.
.
.
第n个小朋友:ave=An-xn+x1 ......
若要结果最小,则就要|x1|+|x2|+|x3|+......+|xn| 最小,也就是要每个小朋友给他左边的那一个小朋友糖的数量之和最小,则一共要给n次;
而我们观察上面推导的式子,发现每一个xi都可以被x1和其他一些量表示,而这些量具有两种性质:1、有规律,2、都是已知量,于是我们可以把它整个看做一个常数(像物理中那样......),存到ci中,于是我们可以推出:xi=x1-ci,ci=c(i-1)-ave+Ai;
即现在要|x1|+|x1-c2|+|x1-c3|+.......+|x1-cn|;
将|x1-ci|看做是数轴上x1到ci的距离,问题变成在数轴有n个点,找到一个点使它到这n个点的距离之和最小,而这个点就是排序后c1~cn的中位数;

思考:

1、耐心的数学推导使我们将一个看似复杂的问题转化为了一个单变量的问题;

2、实际上x1就是一个单变量,它的取值实际上是这个题最本质的问题;
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#define maxn 1000001#define ll long longusing namespace std; int n;ll a[maxn],c[maxn];ll sum,ans,ave; int main() {scanf("%d", &n);for(int i=1; i<=n; ++i) {scanf("%lld", &a[i]);sum+=a[i];}ave=sum/n;for(int i=2; i<=n; ++i) {c[i]=c[i-1]+a[i]-ave;}sort(c+1,c+n+1);ll mid=c[(n>>1)+1];for(int i=1; i<=n; ++i) {ans+=abs(c[i]-mid);}printf("%lld", ans);} 


0 0
原创粉丝点击