传送门
对于 b i b_i bi为正的任务,显然贪心,按 a i a_i ai从小到大排序,当前能力值大于等于 a i a_i ai就选上。
剩下一堆任务,题目变成,选第 i i i个任务需要 a i a_i ai能力值,做完这个任务能力值减少 b i b_i bi。考虑 d p dp dp, f [ i ] [ j ] f[i][j] f[i][j]表示做前 i i i个任务,能力值为 j j j,最多能做多少个任务。
枚举前面的任务,枚举能力值,满足条件则转移。
d p dp dp前要对任务排序,我们考虑按 a i + b i a_i+b_i ai+bi排序,这样显然后面的任务不会影响前面的任务。
C o d e B e l o w : Code \ Below: Code Below:
#include
#define ts cout<<"ok"<
#define ll long long
#define hh puts("")
#define pc putchar
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
using namespace std;
int n,r,cnt1,cnt2,ans,f[105][60005],res;
struct node{
int x,y;
}a[10005],b[10005];
inline int read(){
int ret=0,ff=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') ff=-ff;ch=getchar();}
while(isdigit(ch)){ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*ff;
}
void write(int x){
if(x<0){x=-x;putchar('-');}
if(x>9) write(x/10);
putchar(x%10+48);
}
inline bool cmp1(node A,node B){
return A.x<B.x;
}
inline bool cmp2(node A,node B){
return A.x+A.y>B.x+B.y;
}
signed main(){
n=read(),r=read();
for(int i=1;i<=n;i++){
int x=read(),y=read();
if(y>=0) a[++cnt1]=(node){x,y};
else b[++cnt2]=(node){x,y};
}
sort(a+1,a+cnt1+1,cmp1);
int now=r;
for(int i=1;i<=cnt1;i++){//先把正的都选上
if(now>=a[i].x){
ans++;
now+=a[i].y;
}
else break;
}
sort(b+1,b+cnt2+1,cmp2);
for(int i=1;i<=cnt2;i++){
if(now>=b[i].x&&now>=abs(b[i].y)){
f[i][now-abs(b[i].y)]=1;
res=max(res,1);
for(int j=i-1;j>=1;j--)
for(int k=max(abs(b[i].y),b[i].x);k<=60000;k++)
if(f[j][k]){
f[i][k-abs(b[i].y)]=max(f[i][k-abs(b[i].y)],f[j][k]+1);
res=max(res,f[i][k-abs(b[i].y)]);
}
}
}
write(ans+res);
return 0;
}