BZOJ1465
BZOJ1465: 糖果传递
Time Limit: 2 Sec Memory Limit: 64 MB
Description
老师准备了一堆糖果, 恰好n个小朋友可以分到数目一样多的糖果. 老师要n个小朋友去拿糖果, 然后围着圆桌坐好, 第1个小朋友的左边是第n个小朋友, 其他第i个小朋友左边是第i-1个小朋友. 大家坐好后, 老师发现, 有些小朋友抢了很多的糖果, 有的小朋友只得到了一点点糖果, 甚至一颗也没有 , 设第i个小朋友有ai颗糖果. 小朋友们可以选择将一些糖果给他左边的或者右边的小朋友, 通过”糖果传递”最后使得每个小朋友得到的糖果数是一样多的, 假设一颗糖果从一个小朋友传给另一个小朋友的代价是1, 问怎样传递使得所耗的总代价最小.
Input
第一行一个正整数n,表示小朋友的个数. n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.
Output
输出只有一个数, 表示最小代价.
Sample Input
4
1
2
5
4
Sample Output
4
数据范围
30%的测试数据, n<=1000.
100%的测试数据, n<=1000000.
ai>=0, 保证ai在longint/int范围内, ai的总和在int64/long long范围内.
题目解析:
这道题我刚开始看的时候还以为是一道DP题,然而我又想多了,直到我看了黄学长的博客以后才得出结论666.设\(A_i\)为第i位同学的初始糖的数量.设\(X_1\)为第1位同学要给第n位同学的糖的数量,\(X_i\)为第i位同学要给第i-1位同学的糖的数量,并且设\(ave\)为最终的结果,也就是总数的平均数.
因此我们可以得到:
\(A_1+X_1+X_2=ave\Rightarrow X_2=ave-A_1-X_1=X_1-C_1,C_1 = A_1-ave\).
\(A_2+X_2+X_3=ave\Rightarrow X_3=ave-A_2-X_2=2ave-A_1-A_2-X_1=X_1-C_2,C_2 = A_1+A_2-2ave\)
\(......\)
\(A_n+X_n+X_1=ave\Rightarrow ......\)
所以我们最终得到答案\(ans=|X_1|+|X_1-C_1|+|X_1-C_2|+|X_1-C_3|......|X_1-C_{n-1}|\),而将\(C_i\)放到数轴上面,我们就相当于将问题转化为了在数轴上找一点使得它到所有点的距离之和最小.而这个点就是\(C_i\)的中位数.至于证明我也不知道,不过可以做为一个结论来记.
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1000000 + 5;
int n;
int a[maxn],c[maxn];
int ave;
long long tot;
int abs(int k){
return k > 0 ? k : -k;
}
int main(){
scanf("%d",&n);
for(int i = 1;i <= n; i++){
scanf("%d",&a[i]);
tot += a[i];
}
ave = tot/n;
for(int i = 2;i <= n; i++){
c[i] = c[i-1] + a[i] - ave;
}
sort(c+1,c+n+1);
int mid = c[(n>>1)+1];
long long ans = 0;
for(int i = 1;i <= n; i++)
ans += abs(mid - c[i]);
printf("%lld\n",ans);
return 0;
}