CF1203F2 - Complete the Projects (hard version) 题解

题干

给定任务个数 nn 和初始值 rr,第 ii 个任务至少需要 rraia_i 时才能做,完成后 rr 会增长 bib_i,每次完成任务后的能力值必须大于等于 00,最多能做多少个任务。

思路

一道贪心题,考虑 dp。

对第一个或最后一个阶段进行分类讨论,化原问题为子问题。——某老师

因为 300bi300-300 \le b_i \le 300,显然,分类讨论从 bib_i 入手,分正负两种。

对于 bi0b_i \ge 0 的任务,比较简单,即对应的 aia_i 从小到大排序,当前能力值 rair \ge a_i 就选上。

对于剩下的(bi<0b_i<0)任务,就需要解决“做第 ii 个任务需要 aia_i 的能力值,做完减少 bib_i(此时 bib_i 为原 bib_i 的绝对值),最多能做多少个任务”的问题。这时,dp 就派上用场了。dpi,jdp_{i,j} 表示,做前 ii 个任务,能力值为 jj 时,最多能做几个任务。再优化压缩一下,可成为一维数组(不过还是两重循环)。

dp 前要先对任务进行排序,对于以上两种的 bib_i 要分别用两个数组来装,对于装第一种的数组,以 aia_i 从小到大排序,若相等则 bib_i 更大者优先;对于第二种,则是以 ai+bia_i+b_i 更大者优先。

代码

#include<bits/stdc++.h>
using namespace std;
struct Node {
	int need,val;
}yyx1[111],yyx2[111];
int l1,l2,aa,n,s,dp[66666],ans;
int main() {
	memset(dp,-0x3f,sizeof(dp));
	cin>>n>>s;
	for(int i=1;i<=n;i++) {
		int a,b;
		cin>>a>>b;
		if(b>=0) {
			yyx1[++l1]=Node{a,b};
		}
		else {
			yyx2[++l2]=Node{a,b};
		}
	}
	sort(yyx1+1,yyx1+l1+1,[](Node a,Node b) {if(a.need==b.need)return a.val>b.val; return a.need<b.need;});
	sort(yyx2+1,yyx2+l2+1,[](Node a,Node b) {return a.need+a.val>b.need+b.val;});
	for(int i=1;i<=l1;i++) {
		if(s>=yyx1[i].need) {
			aa++,s+=yyx1[i].val;
		}
	}
	for(int i=0;i<=s;i++)dp[i]=0;
	for(int i=1;i<=l2;i++) {
		for(int j=0;j<=60000;j++) {
			if(j-yyx2[i].val<=60000&&j-yyx2[i].val>=yyx2[i].need) dp[j]=max(dp[j],dp[j-yyx2[i].val]+1);
			ans=max(dp[j],ans);
		}
	} 
	cout<<ans+aa;
	return 0;
}
posted @ 2023-07-18 16:46  cjrqwq  阅读(28)  评论(0)    收藏  举报  来源