[HAOI2008] 糖果传递
非常经典的数学题。
设 \(x_i\) 表示 \(i\) 给右边的人多少糖(如果 \(x_i<0\),就是从右边的人那里拿糖)。先考虑列出方程
\[\left\{\begin{matrix}
a_1-x_1+x_n=\bar a \\
a_2-x_2+x_1=\bar a \\
\cdots \\
a_n-x_n+x_{n-1} =\bar a \\
\end{matrix}\right.
\]
用 \(x_1\) 表示 \(x_2\),\(x_2=a_2+x_1-\bar a\);
用 \(x_2\) 表示 \(x_3\),\(x_3=a_3+x_2-\bar a\);
因此,用 \(x_1\) 表示 \(x_3\),\(x_3=a_3+a_2+x_1-\bar a-\bar a\);
类似的,可知
\[x_i=\sum_{j=2}^i (a_j-\bar a)+x_1\\
\]
换成减法,
\[x_i=x_1-\sum_{j=2}^i (\bar a-a_j)
\]
题目要求最小化 \(\sum |x_i|\)。设 \(s_i=\sum_{j=2}^i (\bar a-a_j)\),即最小化
\[\sum_{i=1}^n |x_1-s_i|
\]
这是一个经典的问题,当 \(x_1\) 取 \(s\) 的中位数时原式最小。
// Title: 糖果传递
// Source: HAOI2008
// Author: Jerrywang
#include <bits/stdc++.h>
#define F first
#define S second
#define pii pair<int, int>
#define ll long long
#define rep(i, s, t) for(int i=s; i<=t; ++i)
#define debug(x) cerr<<#x<<":"<<x<<endl;
const int N=1000010;
using namespace std;
int n, a[N]; ll avg, res, s[N];
int main()
{
#ifdef Jerrywang
freopen("E:/OI/in.txt", "r", stdin);
#endif
scanf("%d", &n);
rep(i, 1, n) scanf("%d", a+i), avg+=a[i];
avg/=n;
rep(i, 2, n) s[i]=s[i-1]+avg-a[i];
sort(s+1, s+n+1);
int j=n/2+1; ll res=0;
rep(i, 1, n) res+=abs(s[j]-s[i]);
printf("%lld", res);
return 0;
}

浙公网安备 33010602011771号