BZOJ 1045 糖果传递
Description
有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。
Input
小朋友个数n 下面n行 ai
Output
求使所有人获得均等糖果的最小代价。
Sample Input
4
1
2
5
4
1
2
5
4
Sample Output
4
HINT
数据规模
30% n<=1000
100% n<=100000
Source
白书上的原题,但是做法的确很神奇。
假设我们最终分糖果分匀时,每个人所拥有的糖果数量为M。我们用xi表示i号给了i-1号xi个糖果(x1表示1号给了4号的糖果数,若xi<0,择表示i-1号给了i号|xi|个糖果),Ai表示每个人原有的糖果数。因此我们可以列出方程。
对于第一个人而言:A1-x1+x2=M → x2=M-A1+x1=x1-C1(规定Ci=ΣAj*(j=1,j<=i)+i*M,C0=0);
对于第二个人而言:A2-x2+x3=M → x3=M-A2+x2=2M-A1-A2+x1(代入x2=M-A1+x1)=x1-C2;
同理...... 第n个人所得的式子是多余的。
所以ans=min(Σ|xi|(i<=n))=min(Σ|x1-Ci|(i=0,i<n))。这个式子的几何意义是给定数轴上的n个点,找出一个点到他们的距离和最近。
这是个很经典的式子,我们最优的x1一定是在所有Ci的中位数上。就这样答案就出来了。(我并不会证明)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 7 #define maxn 1000010 8 long long n,x,a[maxn],c[maxn],m; 9 long long ans; 10 11 int main() 12 { 13 scanf("%lld",&n); 14 for (long long i = 1;i <= n;++i) scanf("%lld",a+i),c[i] = c[i-1]+a[i]; 15 m = c[n]/n; 16 for (long long i = 1;i < n;++i) c[i] -= i*m; 17 sort(c+1,c+n); 18 x = c[n>>1]; 19 ans = abs(x); 20 for (long long i = 1;i < n;++i) 21 ans += abs(c[i]-x); 22 printf("%lld",ans); 23 return 0; 24 }
高考结束,重新回归。