AcWing 125. 耍杂技的牛

题意

奶牛叠罗汉, 这 N 头奶牛中的每一头都有着自己的重量 Wi 以及自己的强壮程度Si

写一个程序确定奶牛排序, 要使得它们的风险值中的最大值尽可能小

第 i 头奶牛的危险系数 = 当前上面所有奶牛的危险系数之和 - 第i头奶牛的强壮值


结论:

将奶牛按照 wi+si 进行升序排序, 风险系数一定是最小的

举个例子:
    给定的  Wi Si 为:
          1 10 3
          2 2  5
          3 3  3 

    没有排序的情况:    Wi Si  危险系数
                  1 10 3    -3   -> 0-3
                  2 2  5    5    -> 10-5
                  3 3  3    9*   -> 12-3
    所以该序列的最终危险系数为 9

    排序的情况:      Wi Si     危险系数
                1  3  3     -3  -> 0-3  
                2  2  5     -2  -> 3-5
                3  10 3      2* -> 5-3
    所以该序列的最终危险系数为 2

所以, 从例子上就可以看出升序排序后所得的解是优于未排序的解的


证明:

我们可以先思考一下, 在排序前和排序后的关系? 如果把第 i 头牛和第 i+1 头牛交换, 会有什么样的影响? 
我们要求的是让最大值尽可能最小, 也就要使得交换前大于交换后
序列: w₁s₁.., wᵢsᵢ, wᵢ₊₁sᵢ₊₁ ... wₙsₙ
第 i 头牛交换前的危险系数

第 i+1 头牛交换前的危险系数

第 i 头牛交换后的危险系数

第 i+1 头牛交换后的危险系数

因为每个式子前面的 sigma 的 1+...+i-1 是交集, 所以我们可以发现 
"交换前后, 其他牛的危险值显然不变, 所以我们只要分析交换前后, 这两头牛的最大危险值即可"

化简后得到

第 i 头牛交换前

第 i+1 头牛交换前

第 i 头牛交换后

第 i+1 头牛交换后

将交换前后进行对比
ps: ∀wᵢ,sᵢ∈Z⁺

因为题目的要求是最大值中风险值最小
即交换后的max(wᵢ₊₁-sᵢ, -sᵢ₊₁)(后)需要小于等于 交换前的max(−si, wᵢ-sᵢ₊₁)(前)

第 i 头牛交换前后的对比: 
     前      后
    -sᵢ 和 wᵢ₊₁-sᵢ
两边同时加上一个sᵢ, 可以发现 wᵢ₊₁-sᵢ > -sᵢ

第 i+1 头牛交换前后的对比: 
      前        后
    wᵢ-sᵢ₊₁ 和 -sᵢ₊₁
两边同时减去一个 sᵢ₊₁, 可以发现 wᵢ-sᵢ₊₁ > -sᵢ₊₁,

即最大风险范围是 [wᵢ-sᵢ₊₁, wᵢ₊₁-sᵢ]
所以我们只要对比 wᵢ₊₁-sᵢ 和 wᵢ-sᵢ₊₁ 就行即可

当 wᵢ-sᵢ₊₁ >= wᵢ₊₁-sᵢ 时, wᵢ+sᵢ >= wᵢ₊₁+sᵢ₊₁ 时, 交换后更优
当 wᵢ-sᵢ₊₁ < wᵢ₊₁-sᵢ 时, wᵢ+sᵢ < wᵢ₊₁+sᵢ₊₁ 时, 交换前更优

所以们让按照 wᵢ+sᵢ 进行排序, 当存在逆序时就交换
然后更具题意算出每头牛的危险值记录其中最大值即可
先求出一个最大值, 因为要尽可能小, 所以交换后的最大值要小于交换前的最大值(题意), 然后就推出了最优的排序方案.
hh, 我是这么理解的
感觉有点像构造, 根据题意构造出来一个符合要条件的方案...比较菜, 如有错误希望大佬们可以指出
AC代码
#include <iostream>
#include <algorithm>

#define fs first
#define sc second
using namespace std;

const int MAXN = 50010;
typedef pair<int, int> pii;

int n;
pii cow[MAXN];

int main()
{
    cin >> n;
    for (int i = 0; i < n; ++ i)
    {
        int w, s; cin >> w >> s;
        cow[i] = {w + s, w};        // 按照推出的结果排序
    }
    // 根据上文说法这样的排序是最优的
    sort(cow, cow + n);
    int res = -2e9, sum = 0;
    for (int i = 0; i < n; ++ i)
    {
        int w = cow[i].sc, s = cow[i].fs - w;
        res = max(res, sum - s);   // 之前牛的总重量 - 当前牛的强壮值 = 危险系数 
        sum += w;   // wi-1 头牛的累加和
    }
    cout << res << endl;
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值