题目

A Communist regime is trying to redistribute wealth in a village. They have have decided to sit everyone around a circular table. First, everyone has converted all of their properties to coins of equal value, such that the total number of coins is divisible by the number of people in the village. Finally, each person gives a number of coins to the person on his right and a number coins to the person on his left, such that in the end, everyone has the same number of coins. Given the number of coins of each person, compute the minimum number of coins that must be transferred using this method so that everyone has the same number of coins.

一个村庄重新分配财富。 他们已经决定让每个人围坐在一张圆桌旁。 首先,每个人都将其所有财产转换为等值的硬币,这样硬币的总数就可被村庄中的人数整除。 最后,每个人都给右边的人一些硬币,给左边的人一些硬币,每个人都有相同数量的硬币。 给定每个人的硬币数量,计算必须使用此方法转移的最小硬币数量,以便每个人都拥有相同数量的硬币。

输入格式

There is a number of inputs. Each input begins with \(n (n < 1000001)\), the number of people in the village. n lines follow, giving the number of coins of each person in the village, in counterclockwise order around the table. The total number of coins will fit inside an unsigned 64 bit integer.

有多组输入。 每个输入均以数字\(n(n <1000001)\)开头,即人数.接下来\(n\)行,以逆时针方向给出村庄中每个人的硬币数量。 硬币总数将是一个无符号的64位整数。

输出格式

For each input, output the minimum number of coins that must be transferred on a single line.

对于每组输入,输出转移的最小硬币数。

输入样例

3
100
100
100
4
1
2
5
4

输出样例

0
4

题解

这道题感觉有点像数学题啊

因为一个人只能左右传硬币,所以只需要考虑左右

而每个人最开始的硬币数和最终的硬币数都是已知的,所以列方程即可

设\(coin_i\)为最开始每个人的硬币数量,\(pass_i\)为第\(i\)个人给逆时针方向的人(\(i-1\))的硬币数量,\(x\)为最终每个人的硬币数量.

这时候可能有的人就会疑惑了,为啥只给逆时针方向的人不给顺时针方向的人?

我们假设一下,\(1\)号给\(2\)号\(5\)个硬币,\(2\)号给\(1\)号\(3\)个硬币,一共转移了\(8\)个硬币,何必这么麻烦?直接让\(1\)号给\(2\)号\(2\)个硬币不就得了? 这样只需要转移\(2\)个硬币了.

注意,这个硬币数量可以是负数,也就是说,\(1\)号给\(6\)号\(-2\)个硬币,相当于6号给1号\(2\)个硬币

所以,相邻两人之间只会有一次硬币转移.

那我们擦去顺时针的:

然后就可以开始列式子了:

\(x=coin_1+pass_2-pass_1\)

\(x=coin_2+pass_3-pass_2\)

\(\dots\)

\(x=coin_n+pass_1-pass_n\)

移项

\(pass_2=x-coin_1+pass_1\)

\(pass_3=x-coin_2+\bm{pass_2}
\\ \ \ \ \ \ \ \ \ \ \ = x-coin_2+\bm{x_1-coin_1+pass_1}
\)

\(\dots\)

由题意,我们应该让\(\sum_{i=1}^n pass_i\)最小

为了方便描述,再设一个数组\(b_i\),使\(b_0=0\),\(b_i=coin_i+b_{i-1}-x\)

这样就可以方便的表示\(pass_i\),再表示一遍

\(pass_2=pass_1+x-coin_1
\\ \ \ \ \ \ \ \ \ \ \ = pass_1 - (coin_1-x)
\\ \ \ \ \ \ \ \ \ \ \ = pass_1 - b_1
\)

\(pass_3=\bm{pass_2}+x-coin_2
\\ \ \ \ \ \ \ \ \ \ \ = \bm{pass_1 - b_1} +x - coin_2
\\ \ \ \ \ \ \ \ \ \ \ = pass_1 - (\bm{coin_2+b_1-x})
\\ \ \ \ \ \ \ \ \ \ \ = pass_1 - \bm{b_2}
\)

\(\dots\)

所以

\(\sum_{i=1}^npass_i = pass_1+pass_2+pass_3+\dots+pass_n
\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ = |pass_1 - b_1|+|pass_1 - b_2| + \dots + |pass_1 - b_{n-1}|
\)

注意,这个式子相当于数轴上\(b_1,b_2,b_3,b_4\cdots\)到\(pass_1\)的距离之和,那么使这个距离之和最小即可

这里我们可以就用中位数的性质了:

在数轴上所有n个点中,中位数离所有点的距离之和最小

求出最小的和输出即可

理解

对于这个数轴,中位数为2,与其他点距离的和为6

如果不选择中位数,比如选择1,那么与其他点距离的和为7

形象的理解,当\(pass_1\)向左移动一个单位长度时,虽然有两个点的距离缩小了\(d\),但是有3个点的距离增加了\(d\),显然结果变大

若移动两个单位长度,同理结果大于移动一个单位长度,所以当选择中位数时,结果最小.

如果出现偶数个点,

\([2,3]\)中任意一个点皆可做\(pass_1\),由于\(pass_1\)为整数并且为了写代码方便,取端点值即可

证明

  1. 给定一个从小到大的数列\(x_1,x_2,\dots x_n\)

  2. 设\(x\)是从\(x1\)到\(x_n\)与其绝对差之和最小的数.

  3. 当\(x\)在\(x_1\)与\(x_n\)之间,\(x\)与\(x_1\),\(x_n\)的距离和就是\(x_1\)到\(x_n\)的距离,

    若不在\(x_1\)与\(x_n\)之间,\(x\)与\(x_1\),\(x_n\)的距离和还要额外加上一段,

    则\(x\)位于\(x_1\)与\(x_n\)之间.

  4. 由于\(x_1, x_n\)与它们之间的任意一点的距离之和(\(|x_i-x_1|+ |x_i- x_n\)|)都相等,等于\(x_n一x_1\),因此不需要考虑\(x_1, x_n\).

  5. 由第3点可得,\(x\)位于\(x_2\)与\(x_{n-1}\)之间,且\(x\)与\(x_2,x_{n-1}\)的距离和相等,不需要考虑.

  6. 依次类推,\(x\)就是该数列中间的那个数,或者是中间的那两个数之一, 而这个数就是中位数.

代码

#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 1000000 + 10;
long long coin[maxn], b[maxn], tot, x;
int main() {
int n;
while (~scanf("%d", &n)) {
tot = b[0] = 0;
for (int i = 1; i <= n; i++) {
scanf("%lld", &coin[i]);
tot += coin[i];
}
x = tot / n;
for (int i = 1; i < n; i++) b[i] = coin[i] + b[i - 1] - x;
sort(b, b + n);
long long mid = b[n / 2], ans = 0;
for (int i = 0; i < n; i++) ans += abs(mid - b[i]);
printf("%lld\n", ans);
}
return 0;
}

UVA11300 Spreading the Wealth 题解的更多相关文章

  1. Uva11300 Spreading the Wealth

    设第i个人需要给第i+1个人的金币数为xi(xi为负代表收到钱),列出一大堆方程. 设第i个人给第i-1个人的钱为xi(xi<0表示第i-1个人给第i个人钱).计算出最后每个人应该有的钱m,解方 ...

  2. 【题解】 UVa11300 Spreading the Wealth

    题目大意 圆桌旁边坐着\(n\)个人,每个人有一定数量的金币,金币的总数能被\(n\)整除.每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数量相等.您的任务是求出被转手的金币的数量的最小值. ...

  3. (洛谷P2512||bzoj1045) [HAOI2008]糖果传递 || 洛谷P4016 负载平衡问题 || UVA11300 Spreading the Wealth || (洛谷P3156||bzoj3293) [CQOI2011]分金币

    bzoj1045 洛谷P4016 洛谷P2512 bzoj3293 洛谷P3156 题解:https://www.luogu.org/blog/LittleRewriter/solution-p251 ...

  4. UVA11300 Spreading the Wealth 数学

    前方数学警告 题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&am ...

  5. UVa 11300 Spreading the Wealth(有钱同使)

    p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: "Times New ...

  6. UVA 11300 Spreading the Wealth (数学推导 中位数)

    Spreading the Wealth Problem A Communist regime is trying to redistribute wealth in a village. They ...

  7. uva 11300 - Spreading the Wealth(数论)

    题目链接:uva 11300 - Spreading the Wealth 题目大意:有n个人坐在圆桌旁,每个人有一定的金币,金币的总数可以被n整除,现在每个人可以给左右的人一些金币,使得每个人手上的 ...

  8. Uva 11300 Spreading the Wealth(递推,中位数)

    Spreading the Wealth Problem A Communist regime is trying to redistribute wealth in a village. They ...

  9. Math - Uva 11300 Spreading the Wealth

    Spreading the Wealth Problem's Link ---------------------------------------------------------------- ...

随机推荐

  1. STL常用序列容器

    这里简要的记述一下STL常用容器的实现原理,要点等内容. vector vector是比较常用的stl容器,用法与数组是非类似,其内部实现是连续空间分配,与数组的不同之处在于可弹性增加空间,而arra ...

  2. Spring Boot 集成 Swagger 构建接口文档

    在应用开发过程中经常需要对其他应用或者客户端提供 RESTful API 接口,尤其是在版本快速迭代的开发过程中,修改接口的同时还需要同步修改对应的接口文档,这使我们总是做着重复的工作,并且如果忘记修 ...

  3. 【python-opencv】读取、显示、写入图像

    1.读取图像 import cv2 image=cv2.imread("dog2.jpg",1) 说明: 第二个参数是一个标志,它指定了读取图像的方式. cv.IMREAD_COL ...

  4. 「MoreThanJava」Java发展史及起航新世界

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  5. JDK8在泛型类型推导上的变化

    概述 JDK8升级,大部分问题可能在编译期就碰到了,但是有些时候比较蛋疼,编译期没有出现问题,但是在运行期就出了问题,比如今天要说的这个话题,所以大家再升级的时候还是要多测测再上线,当然JDK8给我们 ...

  6. Python模拟用户登录场景

    简单模拟登录场景,将已知的用户名及密码固化,通过用户输入内容和已固化的内容比较进行判断用户名和密码是否输入正确. 在用户输入时,将密码隐藏需要导入模块getpass import getpass _u ...

  7. el-table 表格加图片、加音频、加序号、多级动态表头

    elemnet-ui组件库大家应该不陌生,在展示多条结构类似的数据方面,el-table可谓扛把子,不仅可以把数据展示的整齐,还支持排序.筛选或其他自定义操作.那么,除了上述的基本功能外,你还遇到过哪 ...

  8. Spring AOP—注解配置方法的使用

    Spring除了支持Schema方式配置AOP,还支持注解方式:使用@AspectJ风格的切面声明. 1 启用对@AspectJ的支持 Spring默认不支持@AspectJ风格的切面声明,为了支持需 ...

  9. 存储系列之 DAS、SAN、NAS三种常见架构概述

    随着主机.磁盘.网络等技术的发展,对于承载大量数据存储的服务器来说,服务器内置存储空间,或者说内置磁盘往往不足以满足存储需要.因此,在内置存储之外,服务器需要采用外置存储的方式扩展存储空间,今天在这里 ...

  10. RabbitMQ是什么

    1.引入MQ 1.1什么是MQ ​ MQ(Message Quene):翻译为 消息队列,通过典型的 生产者 和 消费者 模型,生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息.因为消息的 ...