题目描述

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

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

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

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

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

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

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

原题链接:AcWing 125. 耍杂技的牛

备用链接:洛谷 P1842 USACO05NOV奶牛玩杂技

提高版:洛谷 P1080 NOIP2012 提高组 国王游戏

思路

  1. 假设存在两头相邻牛其重量和强壮度分别为分别是 wi, wi+1, si, si+1w_i,\ w_{i+1},\ s_i,\ s_{i+1}

  2. 则构建针对这两头牛位置交换的表格

    牛 i 的危险值 牛 i+1 的危险值
    交换前 w1+w2+...+wi1siw_1+w_2+...+w_{i-1}-s_i w1+w2+...+wi1+wisi+1w_1+w_2+...+w_{i-1}+w_i-s_{i+1}
    交换后 w1+w2+...+wi1si+1w_1+w_2+...+w_{i-1}-s_{i+1} w1+w2+...+wi1+wi+1siw_1+w_2+...+w_{i-1}+w_{i+1}-s_i
  3. 为了方便比较大小关系我们将得到的值减去出现的公共项 w1+w2+...+wi1w_1+w_2+...+w_{i-1} 并加上 si+si+1s_i+s_{i+1} 就可以化简得到以下的表格

    牛 i 的危险值 牛 i+1 的危险值
    交换前 si+1s_{i+1} wi+siw_i+s_i
    交换后 sis_i wi+1+si+1w_{i+1}+s_{i+1}
  4. 这时候我们需要注意到 牛 i+1 交换前的危险值必然大于 牛 i 交换后的危险值,同样的牛 i+1 交换后的危险值必然大于 牛 i 交换前的危险值,如果能确定 牛 i+1 交换前后的危险值的大小就可以唯一地确认整体的交换前后的关系,我们假定这样的情况 wi+si>wi+1+si+1w_i+s_i > w_{i+1}+s_{i+1} 也就意味着当牛 i牛 i+1 交换位置后得到的体系一定比交换前的系统最大危险值小

  5. 综上,我们得到了这样的结论:针对某两头相邻牛将体重值与强壮值之和小的放在体重值与强壮值之和大的上面得到的两头牛的危险值一定会更小

  6. 将这个结论推广就可以得到这样的结论:将牛的体重值与强壮值升序排列得到的最大危险值一定最小(这个过程可以理解为排序中的冒泡排序)

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N = 50010;

int n;
pair<int, int> cow[N];

int main(){
cin>>n;
for(int i = 0; i < n; i++){
int w, s;
scanf("%d%d", &w, &s);
cow[i].first = s+w;
cow[i].second = w;
}

sort(cow, cow+n);

int ans = -2e9, sum = 0;
for(int i = 0; i < n; i++){
int w = cow[i].second, s = cow[i].first-w;
ans = max(ans, sum-s);
sum+=w;
}
cout<<ans;
return 0;
}