[bzoj1045]糖果传递
设x[i]为i往左传递的糖果数,当x[i]<0时表示i-1给i传递了|x[i]|个糖果,每个人平均分到ave个糖果,第i个人的初始糖果数为a[i]。
那么就有如下方程组:
a[1]-x[1]+x[2]=ave --> x[2]=ave+x[1]-a[1]=x[1]+(ave-a[1])
a[2]-x[2]+x[3]=ave --> x[3]=ave+x[2]-a[2]=ave+(ave+x[1]-a[1])-a[2]=x[1]+(ave-a[2])+(ave-a[1])
(下略)
那么可以令c[i]=c[i-1]+(-ave+a[i])=c[i-1]+a[i]-ave
则方程又可以化为x[i]=x[1]-c[i]
则目标z=∑x[i]=∑|x[1]-c[i]|
将c[i]看作直线上的一个点,那么也就是求一个点到任何一个点c[i]的总距离和最小,也就是这些点排序后的中点。

1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <map> 7 #include <string> 8 #include <vector> 9 #include <stack> 10 using namespace std; 11 12 const int N=2000000; 13 int n,a[N],c[N],mid; 14 long long ave,ans; 15 int main(){ 16 scanf("%d",&n); 17 for(int i=1;i<=n;i++)scanf("%d",&a[i]),ave+=a[i]; 18 ave/=n; 19 for(int i=1;i<=n;i++)c[i]=c[i-1]+a[i]-ave; 20 sort(c+1,c+1+n); 21 mid=((n&1?c[n>>1|1]:c[n>>1])+c[n>>1|1])/2; 22 for(int i=1;i<=n;i++)ans+=abs(c[i]-mid); 23 printf("%lld\n",ans); 24 }