参考算法竞赛入门经典训练指南

/*
最后每个人的金币:M = (A1+A2+...+An)/n(设当前每个人的金币为Ai)
设xi表示i给i+1传递给了xi个金币(xn表示n给1传递了xn个金币)

为什么只表示第i给人给第i+1个人的金币数量?因为就算是i+1给i x个金币也可以表示i给i+1 (-x)个金币
那么每个人都满足方程组:
A1+xn-x1 = M
A2+x1-x2 = M
A3+x2-x3 = M
...
An+xn-1-xn = M

而最后答案就是求min(x1+x2+...+xn)
x1 = A1+xn-M
x2 = A2+x1-M = A2+A1+xn-M-M=A1+A2+xn-2M
x3 = A3+x2-M = A3+A2+A1+xn-M-M-M=A1+A2+A3+xn-3M
...
xn = An+xn-1-M=A1+A2+...+An+xn-nM

iM-(A1+A2+...+Ai)=Ci
那么x1+x2+...+xn =xn-C1+xn-C2+...+xn-Cn,因为无论如何传递的金币都是正数,因此可以加上绝对值
|xn-C1|+|xn-C2|+...+|xn-Cn|
那么就变成了数轴上找一个点到所有点距离最短(必须是整数)
那么那个点就是中位数,举一个简单的例子
在一个数轴上任意取6个点(不重合),假设你设定一个原点,左边有4个点,右边有2个点,那么你向左边移动d个单位(不超过左边第4个点),那么
该点到所有点的距离就会减少2d个单位(向左移d个单位左边的所有点的距离之和-4d,右边所有点的距离之和+2d),所以原点取在那里明显不行,因此
放在中位数的地方是最合适的(可以理解为最中间,即左边和右边都有3个点(可以包含),那么无论在那个区间怎么移动都是改变+3d和-3d最后结果不变)
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<cstring>
using namespace std;

const int maxn = 1000000 + 10;
long long A[maxn], tot, M;//A为每个人的金币,tot为总金币,M为最后每个人应该持有的金币
vector<long long>C(maxn);//C为Ci = i*M - (A1+A2+...+Ai)(上述)
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    int n;
    while (cin>>n) {
        memset(A, 0, sizeof(A));
        C.resize(maxn);
        tot = 0;
        for (int i = 1; i <= n; i++) {
            cin >> A[i];
            tot += A[i];
        }
        M = tot / n;//计算M
        long long cur = 0;
        for (int i = 1; i <= n; i++) {
            cur += A[i];
            C[i] = i * M - cur;//计算Ci = i*M - (A1+A2+...+Ai)
        }
        sort(C.begin()+1,C.begin()+n+1);//排序以取中位数
        long long xn = C[(1 + n) / 2];//中位数
        long long res = 0;//结果
        for (int i = 1; i <= n; i++) {
            res += abs(xn - C[i]);//遍历每一个数轴上的点
        }
        cout << res << endl;//输出
    }
    return 0;
}

UVA11300 Spreading the Wealth 分金币 C++ (数学推导)相关推荐

  1. UVA11300 Spreading the Wealth

    UVA11300 Spreading the Wealth 思路  对于这道题,我们可以将其转化为一道线性代数的问题,设第iii个人的初始值为AiA_{i}Ai​,第iii个人给第i−1i-1i−1个 ...

  2. UVa11300 Spreading the Wealth(数学问题)

    题意:给出n个人,每个人有一些金币,可以给一些金币左边或者右边的人,最终使得每个人有相同的金币,问最小的转移金币是多少? 思路:可以假定给金币方向是逆时间方向,值可能是正负.M表示最终每个人有的金币, ...

  3. UVa11300 - Spreading the Wealth

    题意 n个人围成一圈,每个人都有一定数量的金币,金币总数可被n整除,现可将手中金币给左右相邻的人,最终使每人手中的金币数相等,求最少转移的金币数量. 思路 设a[i]给了a[i-1]x1个金币,从a[ ...

  4. UVa11300 Spreading the Wealth 题解

    非常好的一道数学题. 原题链接(洛谷) 原题链接(UVa) 题目分析 (参考刘汝佳<算法竞赛入门经典 ⋅\cdot⋅ 训练指南>) 本身看起来很复杂.不要急,我们慢慢分析. 首先,每个人最 ...

  5. 分金币(Spreading the Wealth,UVa 11300)

    分金币 题目描述 给定N个人成环状坐,每个人初始分配Ai的金币,金币总数可以被N整除,每个人可以给左右相邻的人一定数量的金币使得最终每个人的金币数量相同,求转移数量最小的方案所转移的总金币数量. N& ...

  6. 《训练指南》中的“突击战”和分金币问题

    又到了周末,发现很堕落啊,眼看都星期天了,赶紧发一篇文章,总结一下上周学的. 原题见UVA11300,Spreading the wealth,和 UVA 11729 Commando War:先说突 ...

  7. 11300 - Spreading the Wealth

    (解方程建模+中位数求最短累积位移) 分金币(Spreading the Wealth, UVa 11300) 圆桌旁坐着n个人,每人有一定数量的金币,金币总数能被n整除.每个人可以给他左右相邻的人一 ...

  8. Spreading the Wealth( UVA - 11300)

    题目链接: Spreading the Wealth UVA - 11300 Problem A Communist regime is trying to redistribute wealth i ...

  9. cogs 1430. [UVa 11300]分金币

    1430. [UVa 11300]分金币 ★☆   输入文件:Wealth.in   输出文件:Wealth.out   简单对比 时间限制:1 s   内存限制:256 MB [题目描述] 圆桌旁坐 ...

最新文章

  1. Python调用MySQL模块初试
  2. 在WPF应用程序中利用IEditableObject接口实现可撤销编辑的对象
  3. linux c 字符串函数 replace indexOf substring 实现
  4. CynosDB技术详解——存储集群管理【文末有福利】
  5. 软件测试工具和报告学习-3月6日
  6. 【快乐水题】412. Fizz Buzz
  7. [pytorch、学习] - 4.6 GPU计算
  8. 分布式Session共享解决方案
  9. 用conda安装虚拟的R环境
  10. vue data数据修改_VUE的数据响应式
  11. SQL:我为什么慢你心里没数吗?
  12. fastadmin model关联模型 关联查询问题
  13. 河北四部门联合打击虚开骗税违法行为
  14. VS2010 C++工程运行提示找不到MSVCP100D.dll
  15. 【网易云课堂】产品运营学习
  16. 【爱加密】防止签名破解
  17. 那些我们卖掉的二手iPhone到底去哪了?
  18. Some Laws in IT
  19. 眼光独到便能发现刷脸支付带来的商机
  20. 某农业学校python(七)

热门文章

  1. windows程序设计笔记5
  2. mac修改vmware flusion网络适配器的nat配置
  3. 高级经济师如何备考!?
  4. 如何用有道云笔记实现网页内容保存、网页剪报
  5. MATLAB 随机数
  6. 片仔癀-DRP分销订货,数据驱动的智能订货、铺货,大幅提升订单处理效率
  7. 对于ip地址(私有ip,公有ip)的理解与总结
  8. pin统一配置及代码自动生成工具
  9. Springboot整合mongo
  10. 怎么把Adobe Reader阅读器的背景颜色改为护眼的颜色