耍杂技的牛

题目描述

农民约翰的 \(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;
}
posted @ 2022-04-18 14:32  INnoVation-V2  阅读(40)  评论(0编辑  收藏  举报