题意
奶牛叠罗汉, 这 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;
}