zoukankan      html  css  js  c++  java
  • 糖果传递(中位数、推公式、贪心)

    题意

    (n)个人坐成一圈,每人有(a[i])个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为(1)。求使所有人获得均等糖果的最小代价。

    数据范围

    (1 leq n leq 1000000)
    (0 leq a[i] leq 2 imes 10^9)

    思路

    不妨设第(n)个人传给第(1)个人(x_1)个糖果(这里是净传递量,即第(n)个人传给第(1)个人的数量减去第(1)个人传给第(n)个人的数量),第(1)个人传给第(2)个人(x_2)个糖果,...,第(n - 1)个人传给第(n)个人(x_n)个糖果

    中位数(b = frac{1}{n}(a_1 + a_2 + dots + a_n)),我们的目标是(min(|x_1| + |x_2| + dots + |x_n|))

    因此我们可以根据数量关系,列出如下方程组:

    [a_1 - x_1 + x_n = b\ a_2 - x_2 + x_1 = b\ dots\ a_n - x_n + x_{n - 1} = b ]

    整理可得:

    [x_1 = x_n - (b - a_1)\ x_2 = x_n - (2b - a_1 - a_2)\ dots\ x_{n - 1} = x_n -((n - 1)b - a_1 - a_2 - dots - a_{n - 1})\ ]

    因此我们的目标函数就转化为了(|x_n - (b - a_1)| + |x_n - (2b - a_1 - a_2)| + dots + |x_n - 0|)

    不妨设(x = x_n)(c_1 = b - a_1, c_2 = 2b - a_1 - a_2, dots ,c_n = 0)

    目标函数转化为(|x - c_1| + |x - c_2| + dots + |x - c_n|)

    这样就转化成了一个特别经典的问题,就是数轴上有(n)个点,问选哪个点到这(n)个点的距离之和最小。取中位数即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 1000010;
    
    int n;
    ll a[N];
    ll q[N];
    
    int main()
    {
        scanf("%d", &n);
        ll sum = 0;
        for(int i = 1; i <= n; i ++) {
            scanf("%lld", &a[i]);
            sum += a[i];
            a[i] += a[i - 1];
        }
        ll b = sum / n;
        for(int i = 1; i <= n; i ++) {
            q[i] = i * b - a[i];
        }
        sort(q + 1, q + n + 1);
        ll ans = 0;
        for(int i = 1; i <= n / 2; i ++) ans += q[n - i + 1] - q[i];
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    浅谈Sass与Less区别、优缺点
    混合开发的几个框架
    什么是Node.js?
    初入AngularJS
    jQuery的效果函数
    jQuery的一些选择器
    CSS3新增的属性有哪些:
    linux 新建用户、用户组 以及为新用户分配权限
    linux各个文件作用
    Linux CentOS6.5 命令修改网络配置
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/14374788.html
Copyright © 2011-2022 走看看