CF864E 题解

思路

显然是个 01 背包问题,背包容量 maxdi1\max d_i-1,每个物品可以的拯救结束时间是 tidi1t_i\sim d_i-1,然后 dpi,jdp_{i,j}dpi,jdp_{i,j} 表示拯救第 1i1\sim i 个物品用了至多 jj 个时间能获得的最大价值)可以从 dpi1,jti+pidp_{i-1,j-t_i}+p_i 转移过来。然后这题要输出方案,所以我们可以设一个 lasti,jlast_{i,j} 数组表示 dpi,jdp_{i,j} 是从 dpi,lasti,jdp_{i,last_{i,j}} 成功转移过来的,最后递归输出。如果 lasti,j=jlast_{i,j}=j 说明没有拯救这个物品,不用输出,直接递归。

注意事项

必须对 did_i 从小到大排序,因为肯定是用结束时间小的去更新结束时间大的物品,具体解释详见这里

代码

# include <bits/stdc++.h>
using namespace std;
struct node {
	int t, d, p, id;
	bool operator < (const node& x) const {
		return d < x.d;
	}
} a[105];
int n, dp[105][2005], m, maxi, lst[105][2005];
vector <int> ans;
inline void dfs (int step, int x) {
	if (! step)
		return ;
	dfs (step - 1, lst[step][x]);
	if (lst[step][x] < x)
		ans.emplace_back (a[step].id);
	return ;
}
int main () {
	ios::sync_with_stdio (0);
	cin.tie (0);
	cout.tie (0);
	cin >> n;
	for (int i = 1; i <= n; ++ i) {
		cin >> a[i].t >> a[i].d >> a[i].p;
		a[i].id = i;
		m = max (m, a[i].d);
	}
	sort (a + 1, a + n + 1);
	for (int i = 1; i <= n; ++ i) {
		for (int j = 1; j < m; ++ j)
			dp[i][j] = dp[i - 1][j], lst[i][j] = j;
		for (int j = a[i].t; j < a[i].d; ++ j)
			if (dp[i - 1][j - a[i].t] + a[i].p > dp[i][j])
				dp[i][j] = dp[i - 1][lst[i][j] = j - a[i].t] + a[i].p;
	}
	for (int i = 1; i < m; ++ i)
		if (dp[n][i] > dp[n][maxi])
			maxi = i;
	dfs (n, maxi);
	cout << dp[n][maxi] << '\n' << ans.size () << '\n';
	for (int i : ans)
		cout << i << ' ';
	return 0;
}
posted @ 2024-03-18 09:57  Vitamin_B  阅读(8)  评论(0)    收藏  举报  来源