【HAOI2008】糖果传递-贪心

Description

  有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。求使所有人获得均等糖果的最小代价。

Input

  小朋友个数n,下面n行 ai

Sample Input

4
1 2 5 4

Sample Output

4


  • 思维难度高的贪心题
  • Q:为什么不能像均分纸牌那样做?A:代价!比如1传一圈给n代价为n,但换一个方向后代价就为1
  • 现在假设编号为i的人初始有Ai个糖果。对于1号来说,他给了n号x1个糖果,还剩A1-x1个;但是因为2号给了他x2个糖果,所以最后还剩A1-x1+x2个糖果。根据题设,该金币数等于M。换句话说,我们得到了一个方程:A1-x1+x2=M。
    同理,对于第2个人,有A2-x2+x3=M。最终,我们可以得到n个方程,一共n个变量,是不是可以直接解方程组了呢?很可惜,还不行。因为从前n-1个方程可以推导出最后一个方程。所以,实际上只有n-1个方程是有用的。
    尽管无法直接解出答案,我们还是可以尝试着用x1表示出其他的xi,则本题就变成了单变量的极值问题。
    对于第1个人,A1-x1+x2=M→x2=M-A1+x1=x1-C1(令C1=A1-M,下面类似)
    对于第2个人,A2-x2+x3=M→x3=M-A2+x2=2M-A1-A2+x1=x1-C2(C2=C1+A2-M)
    对于第3个人,A3-x3+x4=M→x4=M-A3+x3=3M-A1-A2-A3+x1=x1-C3
    .....
    对于第1个人,An-xn+x1=M。这是一个多余的等式,并不能给我们更多的信息。
    我们希望所有的xi的绝对值之和尽量小,即|x1|+|x1-C1|+|x1-C2|+...+|x1-Cn-1|要最小。注意到|xi-Ci|的集合意思是数轴上点x1到Ci的距离,所以问题变成了:给定数轴上的n个点,找出一个到它们的距离之和尽量小的点。
    结论:给定数轴上的n个点,在数轴上的所有点中,中位数离所有顶点的距离之和最小。凡是能转化为这个模型的题目都可以用中位数求解。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#define maxn 1000005
using namespace std;
int n,a[maxn];
long long c[maxn],sum;
int main()
{
	int n; scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]),sum+=a[i];
	sum/=n;
	for(int i=1;i<=n;++i) c[i]+=sum-a[i]+c[i-1];
	sort(c+1,c+n+1);
	int mid=c[n/2]; long long ans=0;
	for(int i=1;i<=n;++i) ans+=abs(mid-c[i]);
	printf("%lld",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/wuwendongxi/p/13334698.html