糖果传递
题目描述
有n个小朋友坐成一圈,每人有a[i]个糖果。
每人只能给左右两人传递糖果。
每人每次传递一个糖果代价为1。
求使所有人获得均等糖果的最小代价。
输入格式
第一行输入一个正整数n,表示小朋友的个数。
接下来n行,每行一个整数a[i],表示第i个小朋友初始得到的糖果的颗数。
输出格式
输出一个整数,表示最小代价。
数据范围
1≤n≤1000000
数据保证一定有解。
输入样例:
4
1
2
5
4
输出样例:
4
首先看数据范围
1≤n≤1000000,不能一组一组移,用数学方法
奇怪的推导
X n 为第n个小朋友给第n-1个小朋友的糖果数量
a
n
s
=
∣
X
1
∣
+
∣
X
2
∣
+
.
.
.
+
∣
X
n
∣
ans = |X_1| + |X_2| + ...+|X_n|
ans=∣X1∣+∣X2∣+...+∣Xn∣
那么第一个小朋友还剩下
A
1
=
A
1
−
X
1
+
X
2
A_1=A_1-X_1+X_2
A1=A1−X1+X2
这时所有人的糖果数量相等,为他们糖果数量的平均数num
A
i
−
X
i
+
X
i
+
1
=
n
u
m
A_i-X_i+X_{i+1} = num
Ai−Xi+Xi+1=num
所以假设
C
i
=
A
i
−
n
u
m
C_i=A_i-num
Ci=Ai−num
则
C
i
=
A
i
+
C
i
−
1
−
n
u
m
C_i=A_i+C_{i-1}-num
Ci=Ai+Ci−1−num
所以
a
n
s
=
∣
X
1
∣
+
∣
X
1
−
C
1
∣
+
∣
X
1
−
C
2
∣
+
.
.
.
+
∣
X
1
−
C
n
−
1
∣
ans=|X_1|+|X_1-C_1|+|X_1-C_2|+...+|X_1-C_n-1|
ans=∣X1∣+∣X1−C1∣+∣X1−C2∣+...+∣X1−Cn−1∣
使ans尽量小,就要找到一个点与这n个点的距离最小,这个点就是它们的中位数
问题就转化为找出n个点的中位数
代码如下:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 2e6+10;
LL a[N];
LL c[N];
int n;
LL num;
LL ans;
int main()
{
scanf("%d", &n);
for(int i = 1;i <= n;i++)
{
scanf("%lld", &a[i]);
num += a[i];
}
num /= n;
a[0] = a[n];
for(int i = 1;i <= n;i++)
c[i] = a[i] + c[i-1] - num;
sort(c+1, c+n+1);
for(int i =1;i <= n/2;i++)
{
ans+=c[n-i+1] - c[i];
}
cout << ans;
return 0;
}