[洛谷P1842] 奶牛玩杂技

时间:2023-11-25 17:31:50

有\(N\)头奶牛,每个奶牛有一个重量\(W[i]\),力量\(S[i]\)。定义每个奶牛的压扁程度为排在它前面的所有奶牛的总量之和减去当前奶牛的力量值。可以改变奶牛的排列顺序,问所有奶牛最大压扁程度可能的最小值


解题思路

没有思路……洛谷给它的难度是黄的,我还是太菜了吧……

其实这道题和国王游戏很像,但是我竟然一点都没联系起来。

假设目前已经确定了前\(i\)个奶牛分别是哪几个,那么影响第\(i\)头奶牛压扁程度的只与它前面是哪些奶牛有关,而与前面那些牛的排列顺序无关——设\(sumw=\sum\limits_{k=1}^{i}w[i]\),则当前奶牛的压扁程度为\(sumw-w[i]-s[i]\),也就是\(sumw-(w[i]+s[i])\)。

下面我们改变奶牛的排列顺序,我们发现当前\(i\)只奶牛确定时,显然第\(i\)只奶牛的\(w[i]+s[i]\)最大时当前奶牛的压扁程度最小。

于是我们得出结论,将所有奶牛按照\(w[i]+s[i]\)从小到大排序得到的结果一定是最优的。

反思

在贪心题中,确定一个,改变别的,这个思想非常重要。考虑影响当前这一步决策的因素到底有哪些,然后再深入分析解决。

Code

答案可能是负数。同时第一只奶牛也是有压扁程度的。

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define int ll
const int MAXN = 10010;
const int MAXM = 20010;
const int INF = 21474837480000;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = 0; int w = 1; register char c = getchar();
for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
if(c == '-') w = -1, c = getchar();
for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
struct Cow{
int w,s;
}a[50010];
int N,Ans,s_w;
inline bool cmp(const Cow& a, const Cow& b){
return (a.w+a.s) < (b.w + b.s);
}
#undef int
int main(){
#define int ll
N = read();
for(int i = 1; i <= N; ++i){
a[i].w = read(), a[i].s = read();
}
sort(a+1, a+N+1, cmp);
s_w = a[1].w;
Ans = -a[1].s;
for(int i = 2; i <= N; ++i){
Ans = Max(Ans, s_w - a[i].s);
s_w += a[i].w;
}
printf("%lld", Ans);
return 0;
}