AcWing 122. 糖果传递【贪心】【《算法竞赛进阶指南》,微软面试题 , HAOI2008】


一、题目链接

AcWing 122. 糖果传递
进阶题目 AcWing 105. 七夕祭


二、题目分析

(一)算法标签

贪心 排序 中位数 推公式

(二)解题思路

x i x_i xi为i号小朋友(初始有 a i a_i ai个糖果)向i-1号小朋友传递的糖果数(其中,i=2,3,4,…,n, 若 x i x_i xi为负数,则表示i-1号小朋友向i号小朋友传递的糖果数),特别地当i=1时, x 1 x_1 x1表示1号小朋友向n号小朋友传递的糖果数

目标: ∣ x 1 ∣ + ∣ x 2 ∣ + ∣ x 3 ∣ + ⋯ + ∣ x n − 1 ∣ + ∣ x n ∣ \vert x_1 \vert + \vert x_2\vert+\vert x_3 \vert+ \dots +\vert x_{n-1} \vert+\vert x_n \vert x1+x2+x3++xn1+xn最小
由题意,可得:
{ x 1 = x 2 + a 1 − a ˉ x 2 = x 3 + a 2 − a ˉ ⋯ x n − 1 = x n + a n − 1 − a ˉ x n = x 1 + a n − a ˉ \begin{cases} x_1=x_2+a_1-\bar a \\ x_2=x_3+a_2-\bar a \\ \cdots \\ x_{n-1}=x_n+a_{n-1}-\bar a \\ x_n=x_1+a_n-\bar a \\ \end{cases} x1=x2+a1aˉx2=x3+a2aˉxn1=xn+an1aˉxn=x1+anaˉ

n个方程相加得到一个恒等式: 0 = a 1 + a 2 + ⋯ + a n − n a ˉ 0=a_1+a_2+\cdots+a_n-n\bar a 0=a1+a2++annaˉ,所以上面的方程组有n-1个有效方程,n个未知元,那么可以用其中一个未知元来表示其它n-1个未知元

对上述方程组作一下变换,可以得到:
{ x 1 = x 1 − 0 x 2 = x 3 − [ ( n − 1 ) a ˉ − a n − a n − 1 − ⋯ − a 2 ] ⋯ x n − 1 = x 1 − ( 2 a ˉ − a n − a n − 1 ) x n = x 1 − ( a ˉ − a n ) \begin{cases} x_1=x_1-0 \\ x_2=x_3-[(n-1)\bar a - a_n-a_{n-1}-\cdots-a_2]\\ \cdots \\ x_{n-1}=x_1-(2\bar a-a_n-a_{n-1}) \\ x_n=x_1-(\bar a - a_n) \\ \end{cases} x1=x10x2=x3[(n1)aˉanan1a2]xn1=x1(2aˉanan1)xn=x1(aˉan)
等价于下面方程组:
{ x 1 = x 1 − c 1 x 2 = x 3 − c 2 ⋯ x n − 1 = x 1 − ( 2 a ˉ − a n − a n − 1 ) x n = x 1 − ( a ˉ − a n ) \begin{cases} x_1=x_1-c_1 \\ x_2=x_3-c_2\\ \cdots \\ x_{n-1}=x_1-(2\bar a-a_n-a_{n-1}) \\ x_n=x_1-(\bar a - a_n) \\ \end{cases} x1=x1c1x2=x3c2xn1=x1(2aˉanan1)xn=x1(aˉan)

其中,
{ c 1 = 0 c 2 = ( n − 1 ) a ˉ − a n − a n − 1 − ⋯ − a 2 ⋯ c n − 1 = 2 a ˉ − a n − a n − 1 c n = a ˉ − a n \begin{cases} c_1=0 \\ c_2=(n-1)\bar a - a_n-a_{n-1}-\cdots-a_2 \\ \cdots \\ c_{n-1}=2\bar a-a_n-a_{n-1}\\ c_n=\bar a - a_n\\ \end{cases} c1=0c2=(n1)aˉanan1a2cn1=2aˉanan1cn=aˉan
可以发现当 i > 1 i>1 i>1 c i = c i + 1 + a ˉ − a i c_i=c_{i+1}+\bar a -a_i ci=ci+1+aˉai
回到目标:
此时,
∣ x 1 ∣ + ∣ x 2 ∣ + ∣ x 3 ∣ + ⋯ + ∣ x n − 1 ∣ + ∣ x n ∣ \vert x_1 \vert + \vert x_2\vert+\vert x_3 \vert+ \dots +\vert x_{n-1} \vert+\vert x_n \vert x1+x2+x3++xn1+xn最小
等价于 ∣ x 1 − c 1 ∣ + ∣ x 1 − c 2 ∣ + ∣ x 1 − c 3 ∣ + ⋯ + ∣ x 1 − c n − 1 ∣ + ∣ x 1 − c n ∣ \vert x_1-c_1 \vert + \vert x_1-c_2\vert+\vert x_1-c_3 \vert+ \dots +\vert x_1-c_{n-1} \vert+\vert x_1-c_n \vert x1c1+x1c2+x1c3++x1cn1+x1cn最小 (其中 c 1 , c 2 , ⋯   , c n c_1,c_2,\cdots,c_n c1,c2,,cn 均为常数)
x 1 x_1 x1 c 1 , c 2 , ⋯   , c n c_1,c_2,\cdots,c_n c1,c2,,cn中位数即可使上述式子的值最小
此时,问题转换成了AcWing 104. 货仓选址【贪心】【《算法竞赛进阶指南》】


三、AC代码

解法一:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 1e6 + 10;

int a[N], c[N];
int n;


int main()
{
    cin >> n;
    LL sum = 0;
    for (int i = 1; i <= n; i ++ )
    {
        scanf("%d", &a[i]);
        sum += a[i];
    }
    // 每个小朋友最后的糖果数一样,所以平均数一定是整数
    LL avg = sum / n;
    
    // 求c[i]
    for (int i = n; i > 1; i -- )
        c[i] = c[i + 1] + avg - a[i];
    
    // 找c[i]的中位数
    sort(c + 1, c + 1 + n);
    LL mid = c[1 + n >> 1];
    
    // 求结果
    LL res = 0;
    for (int i = 1; i <= n; i ++ )
        res += abs(c[i] - mid);
    
    cout << res << endl;
    return 0;
}

四、其它题解

AcWing 122. 糖果传递 1

AcWing 122. 糖果传递 2

AcWing 122. 糖果传递【环形纸牌均分问题】

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值