ACcoders Problem 2042 题解

文章描述了一个数学问题,涉及n个小朋友和他们的糖果分配。每个小朋友有特定数量的糖果,目标是通过最小代价的传递使得所有小朋友的糖果数量相等。解决方案涉及到计算平均数,建立传递模型,并通过寻找中位数来确定最小代价。最后给出了C++代码实现。
摘要由CSDN通过智能技术生成

题意

n n n 个小朋友,他们围成了一个圈,每个人有 a i a_{i} ai 个糖果。每人每次传递一个糖果代价为 1 1 1。求使所有小朋友获得均等糖果的最小代价。

思路

我们设 x i x_{i} xi 为第 i i i 个小朋友传给第 i + 1 i+1 i+1 个小朋友的糖果数量, a v e ave ave 为所有小朋友的糖果的平均数。则有:
a v e = 1 n ( a 1 + a 2 + … a n ) ave=\frac{1}{n}(a_{1}+a_{2}+…a_{n}) ave=n1(a1+a2+an)

a i − x i + x i − 1 = a v e a_{i}-x_{i}+x_{i-1}=ave aixi+xi1=ave
我们再将第二个式子展开,即:
a 1 − x 1 + x n = a v e a_{1}-x_{1}+x_{n}=ave a1x1+xn=ave

a 2 − x 2 + x 1 = a v e a_{2}-x_{2}+x_{1}=ave a2x2+x1=ave

… …

a n − x n + x n − 1 = a v e a_{n}-x_{n}+x_{n-1}=ave anxn+xn1=ave
然后再移项
x 1 = x n − ( a v e − a 1 ) x_{1}=x_{n}-(ave-a_{1}) x1=xn(avea1)

x 2 = x n − ( a v e − a 2 ) x_{2}=x_{n}-(ave-a_{2}) x2=xn(avea2)

… …

x n = x n − 1 − ( a v e − a n ) x_{n}=x_{n-1}-(ave-a_{n}) xn=xn1(avean)
我们再将其逐个由之前的式子替换
x 1 = x n − ( a v e − a 1 ) x_{1}=x_{n}-(ave-a_{1}) x1=xn(avea1)

x 2 = x n − ( 2 × a v e − a 1 − a 2 ) x_{2}=x_{n}-(2\times ave-a_{1}-a_{2}) x2=xn(2×avea1a2)

… …

x n = x n − ( n × a v e − a 1 − a 2 − … − a n ) x_{n}=x_{n}-(n×ave−a_{1}−a_{2}−…−a_{n}) xn=xn(n×avea1a2an)
因为我们要求的是传递最小的代价,即为:
∣ x 1 ∣ + ∣ x 2 ∣ + … + ∣ x n ∣ |x_{1}|+|x_{2}|+…+|x_{n}| x1+x2++xn
我们发现,可以将原来的式子带入其中,并且此式后面的常数部分我们可以整理一下用 c i c_{i} ci 代替。
∣ x n − ( a v e − a 1 ) ∣ + ∣ x n − ( 2 × a v e − a 1 − a 2 ) ∣ + … + ∣ x n − ( n × a v e − a 1 − a 2 − … − a n ) ∣ |x_{n}-(ave-a_{1})|+|x_{n}-(2\times ave-a_{1}-a_{2})|+…+|x_{n}-(n×ave−a_{1}−a_{2}−…−a_{n})| xn(avea1)+xn(2×avea1a2)++xn(n×avea1a2an)

∣ x n − c 1 ∣ + ∣ x n − c 2 ∣ + … + ∣ x n − c n ∣ |x_{n}-c_{1}|+|x_{n}-c_{2}|+…+|x_{n}-c_{n}| xnc1+xnc2++xncn
现在,我们就可以将其转化为一个数轴上求距离的集合问题。我们再将 ∣ x n − c 1 ∣ |x_{n}-c_{1}| xnc1 ∣ x n − c n − 1 ∣ |x_{n}-c_{n-1}| xncn1 分为一组,随后以此类推,发现 x n x_{n} xn 的取值范围可以用下图来表示(最外层就是 ∣ x n − c 1 ∣ |x_{n}-c_{1}| xnc1 ∣ x n − c n − 1 ∣ |x_{n}-c_{n-1}| xncn1,再向里层就以此类推),发现所有组别的取值范围的交集为中心蓝色的部分,即所有 c i c_{i} ci 的中位数。
在这里插入图片描述
代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[1000001];
int c[1000001];
int n,ave;
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		ave+=a[i];
	}
	ave/=n;
	for(int i=1;i<=n;i++)
		c[i]=c[i-1]+ave-a[i-1];//等价
	sort(c+1,c+n+1);
	int ans=0,mid=c[(n+1)/2];
	for(int i=1;i<=n;i++)
		ans+=abs(mid-c[i]);
	printf("%lld",ans);
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值