题目:
有 n 个小朋友坐成一圈,每人有 a[i]个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为 1。求使所有人获得均等糖果的最小代价。
输入格式
第一行输入一个正整数 n,表示小朋友的个数。接下来 n行,每行一个整数 a[i],表示第 i个小朋友初始得到的糖果的颗数。
输出格式
输出一个整数,表示最小代价。
数据范围
1≤n≤1000000,
0≤a[i]≤2×109,
数据保证一定有解。
输入样例:
4
1
2
5
4
输出样例:
4
分析:
首先分析用什么算法,我第一想到的是二分,但是想了一下后发现如果将糖果传递数作为二分标准,根本没法写(或者说我写不出来),再就是dfs,如果我们将每个点的状态都遍历一遍行不行呢?算一下时间复杂度,每一个点有2种情况,2个点就有2*2种情况,那么如果有1e6个点的话,时间复杂度就是o(),时间复杂度太高了,舍弃;最后就是考虑贪心,将每个点都考虑一遍,时间复杂度是o(n),是可以接受的。
如何进行贪心,首先确定什么是最好的情况,那就是点与点的交换只是单向的,如图1
想想看如果2个点中有平行边,那是不是相当于小朋友A把糖给小朋友B,然后B又把糖给A了呢。
现在开始找规律。见图2
图二
(不懂的话可以去看下货场选址问题)
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1000010;
typedef long long ll;
ll res, mid;
int a[N], p[N];
int main(){
int n;
cin >> n;
for(int i = 1; i <= n; i ++){
scanf("%d", &a[i]);
mid += a[i];
}
mid /= n;
for(int i = 2;i <= n ; i ++){
p[i] = p[i - 1] + mid - a[i];
}
int x1 = 0;
sort(p + 1, p + 1 + n);
if(n % 2 == 0)x1 = (p[n / 2] + p[n / 2 + 1]) / 2;
else x1 = p[n / 2 + 1];
for(int i = 1;i <= n; i ++){
res += abs(p[i] - x1);
}
cout << res;
}