[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; }
本文作者:JosephusWang
本文链接:https://www.cnblogs.com/JosephusWang/p/18146838
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步