题目大意
作为恶魔之馆红魔馆的头脑,魔法使帕秋莉掌握了一种土属性魔法,她使用这种魔法建造了一个大型的土球,并让其一路向下去冲撞障碍。土球有一个稳定性x,如果x < 0,它会立刻散架。每冲撞一个障碍,土球会丧失 a i a_i ai的稳定性,冲撞之后,又会从障碍身上回馈 b i b_i bi的稳定性。帕秋莉想知道,如果合理的安排障碍的顺序,在保证土球不散架的情况下,是否可以将障碍全部撞毁呢?
输入描述
输入一个整数T,代表T组数据,每组数据中:
前一行两个整数n , m,表示障碍个数和土球的稳定性
接下来一行两个整数,分别表示障碍的
a
i
a_i
ai和
b
i
b_i
bi
输入数据满足
∑
\sum
∑n <= 500000, 1<=m<=100000,0<=a,b<=100000
输出描述
若可以,输出“Yes”(不含引号),否则输出“No”(不含引号)
样例输入
1
5 50
49 49
52 0
5 10
26 24
70 70
样例输出
No
思路
我们先考虑容易的。将障碍分为增加稳定性和减少稳定性的两类,我们一定愿意先冲撞增加土球稳定性的障碍,以提升稳定性到最大值来准备冲撞接下来所有减少稳定性的障碍。此为贪心第一步。
在增加土球稳定性的障碍中,我们一定愿意先冲撞 a i a_i ai小的障碍,这样我们才不会一冲就散架。而且这一过程我们土球稳定性一直在增加,需要顾虑的只有 a i a_i ai。反之,假设我们不去区分增稳和减稳两类土球,只考虑 a i a_i ai小的,那么如果我们撞了一个减稳的障碍,土球稳定性就会减小,后面再遇到 a i a_i ai大的障碍,就散架了。
按照现在我们考虑的模式,就算我们一冲就散架,也不会出现更优的贪法了,因为在增稳障碍中我们都无法冲过,就算我们去冲 a i a_i ai更小的降稳障碍,虽然一时冲过,但最后土球稳定性一定降低,再冲 a i a_i ai较大的增稳障碍更冲不过了。故这种贪法是最优的。此为贪心第二步。
然后我们考虑减稳的障碍如何去冲。由贪心的思想,设冲撞顺序(A,B)优于(B,A),冲撞该顺序中第一个障碍前土球的稳定性为 m 1 m_1 m1,冲撞第一个障碍后土球的稳定性为 m 2 m_2 m2。对于(A,B),有 m 2 = m 1 − a A + b A m_2=m_1-a_A+b_A m2=m1−aA+bA,对于(B,A),有 m 2 = m 1 − a B + b B m_2=m_1-a_B+b_B m2=m1−aB+bB,若能成功冲撞第二个障碍,则分别需要满足 m 1 − a A + b A ≥ a B m_1-a_A+b_A≥a_B m1−aA+bA≥aB和 m 1 − a B + b B ≥ a A m_1-a_B+b_B≥a_A m1−aB+bB≥aA,即 m 1 ≥ a A + a B − b A m_1≥a_A+a_B-b_A m1≥aA+aB−bA和 m 1 ≥ a A + a B − b B m_1≥a_A+a_B-b_B m1≥aA+aB−bB,显然 m 1 m_1 m1需要达到的最小值越小,对冲撞成功就越有利,因此 b A > b B b_A>b_B bA>bB,即得到按照回复稳定性从大到小的顺序进行冲撞。此为贪心第三步。
考点
贪心
AC代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=5e5+5;
struct Node{
int a,b;
}node[maxn],node_win[maxn],node_lose[maxn];
bool cmp_win(const Node &A, const Node &B){
return A.a<B.a;
}
bool cmp_lose(const Node &A, const Node &B){
return A.b>B.b;
}
signed main(){
int T,n,m;
cin>>T;
while(T--){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>node[i].a>>node[i].b;
int p=0,q=0,f=0;
for(int i=1;i<=n;i++){
if(node[i].a<=node[i].b)node_win[++p]=node[i];
else node_lose[++q]=node[i];
}
sort(node_win+1,node_win+1+p,cmp_win);
for(int i=1;i<=p;i++){
if(node_win[i].a>m){
f=1;break;
}
m-=node_win[i].a,m+=node_win[i].b;
}
sort(node_lose+1,node_lose+1+q,cmp_lose);
for(int i=1;i<=q;i++){
if(node_lose[i].a>m){
f=1;break;
}
m-=node_lose[i].a,m+=node_lose[i].b;
}
f?puts("No"):puts("Yes");
}
return 0;
}
心得
这是一道究极贪心的题目,一共贪了三次心,是一道兼具定性的贪心思想和定量的贪心思想的题目,是非常值得深入理解的。