【题目描述】
有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。
【数据范围】
n<=1e6
【分析】
一道看上去很难,分析起来很烦,写起来很水的省选题。
首先可以算出每个人最后的糖果数是总数的平均数,设为ave。
设表示第i个人给第i-1个人的糖果数,而表示第1个人给第n个人的糖果数(若<0就是第i-1个人给第i个人的糖果数),则最后的答案就是。
考虑第1个人,他本来有个糖,给了第n个人个,又由第2个人给了他个,那么他最后的糖果总数就是个。同理对于第2个人,他最后的糖果总数就是个,对于第i个人,他最后的糖果总数就是个。特别的,第n个人最后糖果总数是个。
另一方面有这n个人最后的糖果总数都是ave,于是我们得到了n个方程。但是第n个方程可以由前n-1个推导出来,所以本质上只有n-1个方程。
不妨考虑用表示,设,由易得.。
同理,有,……
所以当ans取到min的时候,最小。不难发现此式中为定值,只有可以改变。考虑其几何意义,上式相当于在x轴给出了n个定点,求一个点使其到这些定点距离之和最小。
这就是一个非常简单的数学问题了。画个图,运用调整思想不难得到取n个定点的中位数时最优。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int N=1000000+5;
LL a[N],b[N],s=0;
int main(){
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]),s+=a[i];
s/=n;
for (int i=1;i<=n;i++) b[i]=b[i-1]-(a[i]-s);
sort(b+1,b+1+n);
s=0;
for (int i=1;i<=n;i++) s+=abs(b[i]-b[n/2]);
printf("%lld",s);
}