UVA ~ 11300 ~ Spreading the Wealth (数学推导 + 中位数性质)

题意:圆桌旁坐着n个人,每个人有一定数量的金币,金币总数总能被n整除。每个人可以给他左右相邻的人的一些金币,最终使得每个人的金币数目相等。你的任务是求出被转手的金币数量的最小值。比如,n=4,且四个人的金币数量分别为1,2,5,4,只需要转移4枚金币(第3个人给第2个人两枚金币,第2个人和第4个人分别给第1个人1枚金币)即可实现每人手中的金币相等。

思路:首先我们能轻易的计算出最终每个人手中的金币数,记为M。设相邻的两个人i和i-1交换的金币数为为正表示i给了i-1 个金币,为负表示i-1给了i 个金币,X1表示1与N交换的金币数。我们想要最小。这个不等式有N个未知数,无法求解,我们看能不能找到他们之间的一些方程。

第i个人拥有的金币数为,他只和i-1和i+1交换了金币,最终拥有M个金币。所以我们可以得到如下方程:

所以我们可以的得到N个方程。N个未知数,N个方程看起来好像可以解了。实际上并不行,因为我们通过前面的N-1个方程可以推得最后一个方程(有N-1个人交换的金币数,总金币数确定,所以最后一个交换的金币数可以推得),所以最后一个方程没用。但是这样我们依旧可以利用这些方程,我们可以通过x1把其他所有的未知数都表示出来,这样问题变化为了单变量求极值的问题了。

现在我们用x1把其他未知数表示一下:


因为M和A1都已知,我们把记C1=(A1 - M)。同理C2 =(A1 - M + A2 - M), C2 =(C1 + A2 - M),所以,所以 变为 。我们要求该式子的最小值。

我们发现 |X1-C1| 的数学意义跟数轴上两个点间的距离相同,所以我们把C1,C2,C3...作为数轴上的数轴上的点,那么这个式子的意义就变为了找到一个点使所有点到它的距离和最小。其实这个点就是这些数中的中位数。


证明:任意找一个点,假设为上图中的紫色的点,它左边有3个点,右边有两个点。把他往左移动一小段距离,且不碰到离它最近的左边的红点,假设移动距离为d,那么左边三个点距离它的距离减少了3d,而右边两个点距离它的距离增加了2d。总的来说距离之和减少了d。所以中位数位置最优。当有偶数个点,那个点可以位于最中间的两个点之间的任意位置(还是中位数)。

所以这个问题就解决了。

凡是能转化为这个模型的题目都可以用中位数求解

以上内容大部分来自刘汝佳大神的书上,有部分个人想法。


#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005;
int n;
long long A[MAXN], C[MAXN], sum, M;
int main()
{
    ios::sync_with_stdio(false);
    while (cin >> n)
    {
        sum = 0;
        for (int i = 0; i < n; i++)
        {
            cin >> A[i];
            sum += A[i];
        }
        M = sum / n;
        C[0] = 0;
        for (int i = 1; i < n; i++) C[i] = C[i - 1] + A[i] - M;
        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;
}
/*
3
100
100
100
4
1
2
5
4
*/



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值