原问题等价于:先给\(n\)个人排好顺序、叠在一起,然后从顶往底能走即走,问最多能走多少人
注意到一个问题:如果存在两个人\(i,j\)满足\(a_i + b_i < a_j + b_j\)且\(i,j\)两个人都要逃跑,那么\(j\)会在\(i\)之后跑,因为\(i\)的逃跑能力没有\(j\)强,如果\(j\)先逃跑了,那么\(i\)就有可能没法逃跑。
所以对于所有人按照\(a_i + b_i\)从小到大排序,那么逃跑顺序一定是升序的。
最后计算方案使用DP。设\(f_{i,j}\)表示考虑了前\(i\)个人、跑了\(j\)个人之后剩下所有人搭成的人梯的最高高度,转移考虑第\(i\)个人跑不跑即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<cmath>
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c) && c != EOF){
if(c == '-')
f = 1;
c = getchar();
}
if(c == EOF)
exit(0);
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return f ? -a : a;
}
#define PII pair < int , int >
#define st first
#define nd second
int dp[2003][2003] , N , H;
vector < PII > peo;
bool cmp(PII a , PII b){return a.st + a.nd < b.st + b.nd;}
signed main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
N = read();
int sum = 0;
for(int i = 1 ; i <= N ; ++i){
int x = read() , y = read();
peo.push_back(PII(x , y));
sum += x;
}
H = read();
sort(peo.begin() , peo.end() , cmp);
int maxN = 0;
dp[0][0] = sum;
for(int i = 1 ; i <= N ; ++i){
PII t = peo[i - 1];
for(int j = maxN ; j >= 0 ; --j){
if(dp[i - 1][j] + t.nd >= H){
dp[i][j + 1] = max(dp[i][j + 1] , dp[i - 1][j] - t.st);
if(j == maxN) ++maxN;
}
dp[i][j] = dp[i - 1][j];
}
}
cout << maxN;
return 0;
}