题目链接:点击这里
此题刚开始做时没有什么思路,也不知道这么下手,但不可能穷举。由于对于任意一个人
xi
x
i
,只可能向
xi−1
x
i
−
1
或者
xi+1
x
i
+
1
分金币,因此定义
xi
x
i
为编号为
i
i
的人向编号为的人给多少金币,如果
xi<0
x
i
<
0
,则表示实际上是编号为
i−1
i
−
1
的人向编号为
i
i
的人个金币。
现假设有四个人1,2,3,4,编号为
i
i
的人初始有个金币。对于1号来说,给了4号
x1
x
1
个金币,2号给了他
x2
x
2
个金币,因此还剩
A1−x1+x2
A
1
−
x
1
+
x
2
个金币。而我们知道最后每个人的金币数量为平均数,记为
M
M
,因此我们得到方程:
同理,我们可以对每个人列出方程,因此最终可以得到 n n 个方程,一共有个变量,但其实最后一个方程式无效的,实际上只有 n−1 n − 1 个方程式有效的。
我们可以用 x1 x 1 表示每一个变量,再通过 x1 x 1 的极值解得出结果。例如:A1−x1+x2=M→x2=M−A1+x1=x1−C1 A 1 − x 1 + x 2 = M → x 2 = M − A 1 + x 1 = x 1 − C 1
A2−x2+x3=M→x3=M−A2+x2=x1−C2 A 2 − x 2 + x 3 = M → x 3 = M − A 2 + x 2 = x 1 − C 2读者可自行算出 Ci C i ,是一个递推公式,为:
Ci=Ci−1+Ai−M C i = C i − 1 + A i − M
因此,我们希望所有的 xi x i 的绝对值之和最小,即 |x1|+|x1−C1|+...+|x1−Cn−1| | x 1 | + | x 1 − C 1 | + . . . + | x 1 − C n − 1 | 的值要最小。可将这些点画在数轴上可得,其几何意义为未知数到 Ci C i 的距离总和最短。简单分析可得,当取值为中位数时,距离和最短。
由此可得,当输入点为奇数时,取中位数即可计算出结果,当输入点为偶数时,取最中间两个点之间的任意位置即可。
因此不难写出代码如下:
#include <iostream> #include <algorithm> using namespace std; const int maxn = 1000000 + 10; long long C[maxn],M,tot; int main() { int n; while (cin>>n) { tot = 0; long long x = 0; for (int i = 0; i < n; i++) { cin>>x; tot += x; C[i] = tot; } M = tot/n; for (int i = 0; i < n;i++) { C[i] -= M*(i+1);\\递推计算 } sort(C,C+n); long long x1 = C[n/2],ans = 0; for (int i =0; i < n; i++) ans += abs(x1 - C[i]); cout<<ans<<endl; } return 0; }
需要注意的是,此题需要使用
long long
类型才能AC。