• 耍杂技的牛 INnoVation


    题目描述

    农民约翰的 \(N\) 头奶牛(编号为 \(1..N\))计划逃跑并加入马戏团,为此它们决定练习表演杂技。

    奶牛们不是非常有创意,只提出了一个杂技表演:

    叠罗汉,表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。

    奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。

    \(N\) 头奶牛中的每一头都有着自己的重量 \(W_i\) 以及自己的强壮程度 \(S_i\)

    一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。

    您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能的小。

    输入格式

    第一行输入整数 \(N\),表示奶牛数量。

    接下来 \(N\) 行,每行输入两个整数,表示牛的重量和强壮程度,第 i 行表示第 i 头牛的重量 \(W_i\) 以及它的强壮程度 \(S_i\)

    输出格式

    输出一个整数,表示最大风险值的最小可能值。

    数据范围

    \(1≤N≤50000\),
    \(1≤Wi≤10,000\),
    \(1≤Si≤1,000,000,000\)

    输入样例:

    3
    10 3
    2 5
    3 3
    

    输出样例:

    2
    

    算法思路

    假设牛按照初始顺序堆叠起来,从上到下编号依次为1、2、3、4.......

    不失一般性地取出其中两头牛\(i、i+1\),对于这两头相邻的牛,存在以下性质

    性质1:如果\(W_{i+1}+S_{i+1} < W_i + S_i\),那么将两头牛更换位置,整个堆叠的最大危险值不会比更换前更大

    证明:\(max(i) \ge max(i+1)\)

    i处危险值 i+1处危险值 最大风险值
    交换前 \(W_1+W_2+...+W_{i-1}-S_i\) \(W_1+W_2+...+W_i-S_{i+1}\) \(max(I)\)
    交换后 \(W_1+W_2+...+W_{i-1}-S_{i+1}\) \(W_1+W_2+...+W_{i-1}+W_{i+1}-S_i\) \(max(I+1)\)

    证明步骤

    1、对比交换前i+1处危险值和交换后i处危险值,可知交换前的比交换后的多一个\(W_i\),由题知:\(W_i \ge 1\),所以可得\(交换后i处危险值 \le 交换前i+1处危险值\)

    2、再对比交换前i+1处危险值和交换后i+1处危险值,可知两者差异为\(W_i-S_{i+1}\)\(W_{i+1}-S_i\),又由前提知\(W_{i+1}+S_{i+1} < W_i + S_i\),交换可得\(W_{i+1}-S_i < W_i - S_{i+1}\),所以可知\(交换后i+1处危险值 \le 交换前i+1处危险值\)

    3、又因为\(交换前i+1处危险值 \le max(i)\),且\(max(i+1) = 换后i处或i+1处危险值\),因此\(max(i+1) \le max(i)\)

    得证

    又因为假如存在一个最优解不满足\(W_{i+1}+S_{i+1} > W_i + S_i\)性质,那么根据性质1,必然可以对其进行调节交换,使其形成的堆叠最终满足这个性质,而且最大危险值不会变大

    有了这个性质,我们就可以根据\(W_i+S_i\)的值,对整个堆叠进行排序,最终按照这个值从小到大排成堆叠就是一个最优解

    代码实现

    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    typedef pair<int, int> PII;
    
    const int N = 5e4 + 10;
    
    PII a[N];
    int n;
    
    int main(){
        cin >> n;
        for(int x = 0; x < n; x++){
            int w, s;
            cin >> w >> s;
            a[x] = {w + s, w};
        }
        sort(a, a + n);
        int ans = -1e9, weight = 0;
        for(int x = 0; x < n; x++){
            auto c = a[x];
            ans = max(ans, weight - c.first + c.second);
            weight += c.second;
        }
        cout << ans;
    }
    
  • 相关阅读:
    android 14 进度条和拖动条
    android 13 5种click事件不同实现方式 比较
    android 12 click事件的不同实现方式
    android 11 模拟onclick 事件
    android 10 事件
    android 09
    android 08 AndroidManifest.xml
    android 07 22 23没看
    Linux常用命令last的使用方法详解
    Linux TOP命令 按内存占用排序和按CPU占用排序
  • 原文地址:https://www.cnblogs.com/INnoVationv2/p/16159538.html
Copyright © 2020-2023  润新知