现在的位置: 首页 > 综合 > 正文

糖果传递

2018年04月12日 ⁄ 综合 ⁄ 共 1361字 ⁄ 字号 评论关闭

这是5号阿里巴巴的笔试最后以道编程题,挺难的,在考试的时候没有想出来。

网上搜了以下原来就是糖果传递,HAOI的一道题。

哎,人家高中生做的都是这种难度的东西,我研究生都还不会,不如趁早卖水果去吧。

 

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

4

1
2
5
4

Output

4
数据范围
   30%的测试数据, n<=1000.
   100%的测试数据, n<=1000000.
   ai>=0, 保证ai在长整型范围内, ai的总和在int64/long long范围内.

 

首先我们必须知道对一个小朋友来说,糖果可以从他手上传到左边去,也可以传到右边去,也可以左右一边传一些,考试时就被这点给难住了,怎么统一这些可能性呢?

回来参考别人的解法,我们可以看最后这个小朋友总的流入和流出,不必关系具体分配。首先我们定义 Pi 表示第i个小朋友传给左手小朋友的糖果数,这个数可正可负,如果是负数,那就是从左边拿糖果过来,这样传递就统一成一个方向了。

这样最后所有小朋友传递的糖果数加起来,就是最后的传递数咯~ 即  cost = |P1| + |P2|+| P3|....+| Pn|;

但注意每个小朋友的流入流出不是没有限制的,假设最后每个人平均拿到的是avg,那么对第i个小朋友来说,它的流入流出为   P(i+1)-P(i) ,加上原来就有的a[i],必有:

P(i+1)-P(i)+a[i] = avg;  定义 w[i] = avg - a[i] ,表示第i个小朋友这里的流动糖果数量,那么再定义  s[i] = w[1]+ w[2]+ ...+ w[i],s[i]表示什么呢?将这i个小朋友看做一个整体,这个整体内部的传递是忽略的,与外部的传递只有两部分:第i个小朋友从  i+1那里拿过来的糖果:P(i+1),和第1个小朋友传出去的糖果 P(1),

所以 s[i] = P(i+1) -P(1),表示这i个小朋友整体的流动糖果数。

注意w[i]是可以计算的,s[i]自然也是可以计算的,那么由上式得  P(i+1)=s[i]+P1;于是所有Pi都只与P1取值有关了,上式cost最后也只取决于p1一个变量了。

为了再将这个问题规约成我们熟悉的另一个问题,我们令K = -P1:

即:  cost = | 0-K | + | s[1]-K |+| s[2]- K |....+| s[n-1] - K  |;

这个式子熟悉吗?s[1] ....s[n-1] 的值都是已知的,即都是一根横轴上的点,然后k也是横轴上的某一点,cost不就是这些点与k点的距离之和吗?

自然的,k取s[i]的中值就可以了。

所以cost自然也就算出来了。

 

代码稍后再贴。

抱歉!评论已关闭.