【题目大意】
有$n$个小朋友坐成一圈,第$i$个小朋友有$a_i$个糖果,每个小朋友可以向左右两个小朋友传递糖果,每人每次传递糖果要耗费1单位体力,求最少耗费多少体力可以使每个小朋友最后拥有的糖果数相等。
【思路分析】
首先算出最后每个小朋友拥有的平均糖果数$s$,设$X_i$表示第$i$个小朋友给第$i-1$个小朋友的糖果数,$X_1$表示第1个小朋友给第$n$个小朋友的糖果数,若$X_i<0$表示第$i-1$个小朋友给第$i$个小朋友糖果。所以我们可以得出如下的结论:
$$a_1-X_1+X_2=sRightarrow X_2=s-a_1+X_1=X_1-c_1(c_1=a_1-s)$$
$$a_1-X_2+X_3=sRightarrow X_3=2s-a_1-a_2+X_1=X_1-c_2(c_2=2s-a_1-a_2)$$
$$……$$
$$a_n-X_n+X_1=sRightarrow X_1=X_1-c_{n-1}(c_{n-1}=(n-1)*s-a_1-…-a_{n-1})$$
因为$ans=|X_1|+…+|X_n|$,所以我们要保证$|X_i|$之和最小,即
$$|X_1|+|X_1-c_1|+…+|X_1-c_{n-1}|(min)$$
整理过后整个式子中只剩下$X_1$一个变量,这个式子的集合意义就是在数轴上找到一个点$X_1$,使得这个点到$0,c_1,…,c_{n-1}$这$n$个点的距离总和最小,而符合条件的这个点就是这些数值的中位数。
【代码实现】
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define g() getchar() 7 #define rg register 8 #define go(i,a,b) for(rg int i=a;i<=b;i++) 9 #define back(i,a,b) for(rg int i=a;i>=b;i--) 10 #define db double 11 #define ll long long 12 #define il inline 13 #define pf printf 14 using namespace std; 15 int fr(){ 16 int w=0,q=1; 17 char ch=g(); 18 while(ch<'0'||ch>'9'){ 19 if(ch=='-') q=-1; 20 ch=g(); 21 } 22 while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g(); 23 return w*q; 24 } 25 const int N=1000002; 26 int n,a[N],c[N]; 27 ll sum,ans; 28 int main(){ 29 n=fr(); 30 go(i,1,n) a[i]=fr(),sum+=a[i]; 31 int s=sum/n; 32 go(i,2,n) c[i]=c[i-1]+a[i]-s; 33 sort(c+1,c+1+n); 34 int mid=c[n/2+1]; 35 go(i,1,n) ans+=abs(c[i]-mid); 36 pf("%lld ",ans); 37 return 0; 38 }