bzoj1045【haoi2008】糖果传递

1045: [HAOI2008] 糖果传递

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 2790   Solved: 1220
[ Submit][ Status][ Discuss]

Description

有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。

Input

小朋友个数n 下面n行 ai 

Output

求使所有人获得均等糖果的最小代价。 

Sample Input

4
1
2
5
4

Sample Output

4

HINT

100% n<=987654321





最终每个小朋友的糖果数很容易求出来,等于平均数,用ave表示。假设编号为i的小朋友开始有Ai个糖果。Xi表示第i个小朋友给了第i-1个小朋友Xi个糖果,Xi<0表示第i-1个小朋友给了第i个小朋友|Xi|个糖果。则最终的答案ans=|X1|+|X2|+……+|Xn|。

对于第一个小朋友,他给了第n个小朋友X1个糖果,得到第2个小朋友的X2个糖果,最终还剩A1-X1+X2个糖果,即ave个糖果,所以得到方程A1-X1+X2=ave。同理可得A2-X2+X3=ave......

所以得到:

X2=ave-A1+X1=X1-C1 (C1=A1-ave)

X3=2ave-A1-A2+X1+X2=X1-C2 (C2=A1+A2-X2-2ave)

X4=3ave-A1-A2-A3+X1+X2+X3=X1-C3 (C3=A1+A2+A3-X2-X3-3ave)

……

所以ans=|X1|+|X1-C1|+|X1-C2|+......+|X1-Cn-1|,要使ans尽可能小。因为|X1-Ci|的几何意义是数轴上点X1到Ci的距离,所以问题转化为:给定数轴上n个点,找出一个点到各点距离和最小。所以这个点就是中位数。



#include
#include
#include
#include
#include
#define F(i,j,n) for(int i=j; i<=n; i++)
#define MAXN 1000000
#define LL long long
using namespace std;
int n;
LL a[MAXN],f[MAXN],ave=0,ans=0,mid;
int main()
{
	scanf("%d",&n);
	F(i,1,n)
	{
		scanf("%lld",&a[i]);
		ave+=a[i];
	}
	ave/=n;
	f[1]=0;
	F(i,2,n) f[i]=f[i-1]+a[i-1]-ave;
	sort(f+1,f+n+1);
	mid=f[n/2+1];
	F(i,1,n) ans+=abs(f[i]-mid);
	printf("%lld\n",ans);
}


你可能感兴趣的:(好题)