【P2512】[HAOI2008]糖果传递

Palace

2018-10-08 20:51:31

Solution

[走你](https://www.luogu.org/problemnew/show/P2512) ## 思路: 这是个环形的[均分纸牌](https://www.luogu.org/problemnew/show/P1031)。 在这里记录一下zhw的**数学**做法。 我们设$X_i$表示第$i$个人需要给第$i-1$个人的糖果,设最后每人手中都有$ave$块糖,则$ans=\sum_{i=1}^n|X_i|$,那么: $a_i-X_i+X_{i+1}=ave$ 那么, $a_1-X_1+X_2=ave$ $=>$ $X_2=ave-a_1+X_1$ 令$C_1=a_1-ave$ 那么, $X_2=X_1-C_1$ 还有, $a_2-X_2+X_3=ave-a$ $=>$ $X_3=ave+X_2-a_2$ $=>X_3=2×ave-a_1-a_2+X_1$ $=>$ $X_1-C_2$ ... 我们发现$C_i=sum_i-ave×i$,我们就得到了求$C_i$的方法,而对于$X_i=X_1-C_{i-1}$。 所以$ans=\sum_{i=1}^n|X_i|=|X_1-0|+|X_2-C_1|+...+|X_n-C_{n-1}|$ 根据数学知识,这个式子表示$X_1$到数轴上$C_0$ 到 $C_{n-1}$的点的距离之和,所以$X_1$取中位数时,$ans$最小。 ## 代码: ```cpp #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 1000010 #define LL long long using namespace std; LL n, ave, ans; LL a[N], c[N], x[N], cc[N], s[N]; int main() { scanf( "%lld", &n ); for( LL i = 1; i <= n; ++i ) { scanf( "%lld", &a[i] ); s[i] = s[i - 1] + a[i]; } ave = s[n] / n; for( LL i = 1; i <= n - 1; ++i ) { c[i] = s[i] - ( ave * i ); cc[i] = c[i]; } sort( cc + 1, cc + 1 + n - 1 ); x[1] = cc[( n + 1 ) >> 1]; for( LL i = 2; i <= n; ++i ) x[i] = abs( x[1] - c[i - 1] ); x[1] = abs( x[1] ); for( LL i = 1; i <= n; ++i ) ans += x[i]; printf( "%lld\n", ans ); return 0; } ```