【公式】P2512 [HAOI2008]糖果传递

44 篇文章 4 订阅
43 篇文章 1 订阅

原题地址

题目描述
n n n 个小朋友坐成一圈,每人有 a i a_i ai 个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为 1 1 1

输入格式
小朋友个数 n n n,下面 n n n a i a_i ai

输出格式
求使所有人获得均等糖果的最小代价。

输入输出样例
输入 #1

4
1
2
5
4

输出 #1

4

说明/提示
对于 100 % 100\% 100% 的数据 n ≤ 1 0 6 n\le 10^6 n106


思路:

设每个人原来拥有糖果数量为 A i A_i Ai ,每次向右传递数量为 X i X_i Xi (向左为 − X i -X_i Xi ),糖果平均数为 a v g avg avg

则有
原 有 的 − 向 右 传 出 去 的 + 左 边 传 进 来 的 = 平 均 数 原有的-向右传出去的+左边传进来的=平均数 +=

A i − X i + X i + 1 = a v g A_i-X_i+X_{i+1}=avg AiXi+Xi+1=avg
联立方程
{ A 1 − X 1 + X 2 = a v g A 2 − X 2 + X 3 = a v g ⋯ A n − 1 − X n − 1 + X n = a v g A n − X n + X 1 = a v g \left\{ \begin{aligned} A_1-X_1+X_{2}&=avg \\ A_2-X_2+X_{3}&=avg \\ \cdots \\ A_{n-1}-X_{n-1}+X_{n}&=avg \\ A_n-X_n+X_{1}&=avg \\ \end{aligned} \right. A1X1+X2A2X2+X3An1Xn1+XnAnXn+X1=avg=avg=avg=avg
整理得
{ − X 1 + X 2 = a v g − A 1 − X 2 + X 3 = a v g − A 2 ⋯ − X n − 1 + X n = a v g − A n − 1 X 1 − X n = a v g − A n \left\{ \begin{aligned} -X_1+X_{2}&=avg-A_1 \\ -X_2+X_{3}&=avg-A_2 \\ \cdots \\ -X_{n-1}+X_{n}&=avg-A_{n-1} \\ X_{1}-X_n&=avg-A_n \\ \end{aligned} \right. X1+X2X2+X3Xn1+XnX1Xn=avgA1=avgA2=avgAn1=avgAn
其增广矩阵

B = ( A      β ) = [ − 1 1 0 ⋯ 0 0 a v e − A 1 0 − 1 1 ⋯ 0 0 a v e − A 2 ⋮ ⋱ ⋮ ⋮ 0 0 0 ⋯ − 1 1 a v e − A n − 1 1 0 0 ⋯ 0 − 1 a v e − A n ] B=(A \;\;\beta)= \left[ \begin{array}{cccccc|c} -1 & 1 & 0 & \cdots & 0 & 0 & ave-A_1\\ 0 & -1 & 1 & \cdots & 0 & 0 & ave-A_2\\ \vdots & & \ddots& & & \vdots & \vdots\\ 0 & 0 & 0 & \cdots & -1 & 1 & ave-A_{n-1}\\ 1 & 0 & 0 & \cdots & 0 & -1 & ave-A_{n}\\ \end{array} \right] B=(Aβ)=10011100010000100011aveA1aveA2aveAn1aveAn
化为行最简形
[ 1 0 0 ⋯ 0 − 1 ( ∑ i = 1 n − 1 A i ) − ( n − 1 ) a v e 0 1 0 ⋯ 0 − 1 ( ∑ i = 2 n − 1 A i ) − ( n − 2 ) a v e ⋮ ⋱ ⋮ ⋮ 0 0 0 ⋯ 1 − 1 A n − 1 − a v e 0 0 0 ⋯ 0 0 0 ] \left[ \begin{array}{cccccc|c} 1 & 0 & 0 & \cdots & 0 & -1 & (\sum_{i=1}^{n-1}A_i)-(n-1)ave\\ 0 & 1 & 0 & \cdots & 0 & -1 & (\sum_{i=2}^{n-1}A_i)-(n-2)ave\\ \vdots & & \ddots& & & \vdots & \vdots\\ 0 & 0 & 0 & \cdots & 1 & -1 & A_{n-1}-ave\\ 0 & 0 & 0 & \cdots & 0 & 0 & 0\\ \end{array} \right] 10000100000000101110(i=1n1Ai)(n1)ave(i=2n1Ai)(n2)aveAn1ave0
得方程组的解为
{ X 1 = X n + ( ∑ i = 1 n − 1 A i ) − ( n − 1 ) a v e X 2 = X n + ( ∑ i = 2 n − 1 A i ) − ( n − 2 ) a v e ⋮ X n − 1 = X n + A n − 1 − a v e X n = X n ∈ R \left\{ \begin{aligned} X_1&=X_n+(\sum_{i=1}^{n-1}A_i)&-(n-1)ave\\ X_2&=X_n+(\sum_{i=2}^{n-1}A_i)&-(n-2)ave\\ &\qquad \qquad \qquad \vdots \\ X_{n-1}&=X_n+A_{n-1}&-ave\\ X_n&=X_n&\in{\Bbb R}\\ \end{aligned} \right. X1X2Xn1Xn=Xn+(i=1n1Ai)=Xn+(i=2n1Ai)=Xn+An1=Xn(n1)ave(n2)aveaveR
现在要求 ∑ i = 1 n ∣ X i ∣ \sum_{i=1}^{n}|X_i| i=1nXi 的最小值

观察方程组的解,发现所有项都有相同的变量 X n X_n Xn ,所以构造函数
X x = X n + f ( x ) X_x=X_n+f(x) Xx=Xn+f(x)

f ( x ) = ∑ i = x n − 1 A i    − ( n − x ) a v e f(x)=\sum_{i=x}^{n-1}A_i \; -(n-x)ave f(x)=i=xn1Ai(nx)ave
所以
∑ i = 1 n ∣ X i ∣ = ∣ X n + f ( 1 ) ∣ + ⋯ + ∣ X n + f ( n ) ∣ = ∑ i = 1 n ∣ X n + f ( i ) ∣ \sum_{i=1}^{n}|X_i|=|X_n+f(1)|+\cdots+|X_n+f(n)|=\sum_{i=1}^{n}|X_n+f(i)| i=1nXi=Xn+f(1)++Xn+f(n)=i=1nXn+f(i)
∑ i = 1 n ∣ X n + f ( i ) ∣ \sum_{i=1}^{n}|X_n+f(i)| i=1nXn+f(i) 可以看作数轴上的点 X n X_n Xn 到点 − f ( i ) , i ∈ [ 1 , n ] -f(i),i\in [1,n] f(i),i[1,n] 的距离之和

那么 X n X_n Xn 应取最中间的点(高中结论,函数图像为平底锅( n n n 为偶数)或尖底锅( n n n 为奇数))

于是我们只要找到 − f ( i ) , i ∈ [ 1 , n ] -f(i),i\in [1,n] f(i),i[1,n] 的中位数,把他赋值给 X n X_n Xn 即可
将其代入 ∑ i = 1 n ∣ X n + f ( i ) ∣ \sum_{i=1}^{n}|X_n+f(i)| i=1nXn+f(i) 即为本题答案

P S : PS: PS: f ( x ) f(x) f(x) 有递归求法 f ( i ) = f ( i + 1 ) + A i − a v e f(i)=f(i+1)+A_i-ave f(i)=f(i+1)+Aiave ,从后往前循环即可,不要用 f ( x ) = ∑ i = x n − 1 A i    − ( n − x ) a v e f(x)=\sum_{i=x}^{n-1}A_i \; -(n-x)ave f(x)=i=xn1Ai(nx)ave ,后者会导致 T L E TLE TLE


A C AC AC 代码

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define ROF(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
using namespace std;

const int N = 1e6+1;
int n,a[N],f[N];
ll ave=0,ans=0,Xn;

int main(){
	cin>>n;
	FOR(i,1,n){
		cin>>a[i];
		ave+=a[i];
	}
	ave/=n;//由题意,一定能整除
	f[n]=0;
	ROF(i,n-1,1)
		f[i]=f[i+1]+a[i]-ave;
	sort(f+1,f+n+1);
	Xn=-f[(n+1)/2];
	FOR(i,1,n)
		ans+=abs(Xn+f[i]);
	cout<<ans;
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值