[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 }
View Code

 

posted @ 2016-12-31 13:25  KingSann  阅读(122)  评论(0)    收藏  举报