【BZOJ1045】糖果传递
题目
有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。求使所有人获得均等糖果的最小代价。
分析
又是以前弄懂了,第二次做又不会了,下面自己手打一遍数学证明吧
设 give[i]为第i个人给第i-1个人的糖果数量,a[i]为本身的糖果数量
设均等的糖果数为 ave=sum/n
则 a[1]+give[2]-give[1]=ave
a[2]+give[3]-give[2]=ave
·········
移项
give[2]=give[1]+ave-a[1]
give[3]=give[2]+ave-a[2]=give[1]+ave-a[1]+ave-a[2]
可以观察到有一个 ave-a[i]的部分
设b[i]=a[i]-ave 再设c[i]为b数组的前缀和
则有 give[i]=give[1]-c[i-1]
give[1]+give[2]+·······+give[n]=| c[0]-give[1] |+| c[1]-give[1] |+······+| c[n-1]-give[1] |
相当于求数轴上的n个点到一定点的距离和的最小值
就是初一数学学的, 所以give[1]取序列c的中位数即可
代码
#include<bits/stdc++.h> using namespace std; #define N 1001000 #define ll long long ll n,sum,aver,minx,ans; ll a[N],c[N]; inline void read(ll &x) { x=0;char ch=getchar(); while(ch>'9'||ch<'0'){ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();} } int main() { read(n); for(int i=1;i<=n;i++) read(a[i]),sum+=a[i]; aver=sum/n; for(int i=1;i<=n;i++) c[i]=c[i-1]-aver+a[i]; sort(c+1,c+1+n); minx=c[(n+1)>>1]; for(int i=1;i<=n;i++) ans+=abs(c[i]-minx); printf("%lld\n",ans); return 0; }
“Make my parents proud,and impress the girl I like.”