AcWing 288. 休息时间

传送门

思路:

考虑DP,设dp[i][j][1]为牛在前小时休息j个小时且第i个小时休息时,回复的最多体力;dp[i][j][0]为牛在前小时休息j个小时且第i个小时没有休息时,回复的最多体力。

可以把问题分为两部分,首先考虑当牛不能跨天休息时,在第一个小时休息必然无法恢复体力,有dp[1][1][1]=0,dp[i][0][0]=0,其他皆初始为-inf。于是有dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]),dp[i][j][1]=max(dp[i-1][j-1][0],dp[i-1][j-1][1]+U[i])。

最后答案为max(dp[N][B][0],dp[N][B][1])

那么现在可以跨天休息,说明在第一个小时休息时,若第N个小时也休息了,就恢复体力,所以把刚才dp的初始值中dp[1][1][1]改为1,其余不变,再求一次dp,记录dp[N][B][1]为第二次dp的答案。

两次dp的答案取max就是最终的答案了。

[代码:

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
//#define int LL
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#pragma warning(disable :4996)
const int maxn = 4000;
const double eps = 1e-6;
const LL MOD = 998244353;

int N, B;
int U[maxn];
int dp[2][maxn][2];

void solve()
{
	memset(dp, -inf, sizeof(dp));
	dp[1][0][0] = dp[1][1][1] = 0;
	for (int i = 2; i <= N; i++)
	{
		dp[i & 1][0][0] = 0;
		for (int j = 1; j <= B; j++)
		{
			dp[i & 1][j][0] = max(dp[(i - 1) & 1][j][0], dp[(i - 1) & 1][j][1]);
			dp[i & 1][j][1] = max(dp[(i - 1) & 1][j - 1][0], dp[(i - 1) & 1][j - 1][1] + U[i]);
		}
	}
	int ans = max(dp[N & 1][B][0], dp[N & 1][B][1]);
	memset(dp, -inf, sizeof(dp));
	dp[1][1][1] = U[1], dp[1][0][0] = 0;
	for (int i = 2; i <= N; i++)
	{
		dp[i & 1][0][0] = 0;
		for (int j = 1; j <= B; j++)
		{
			dp[i & 1][j][0] = max(dp[(i - 1) & 1][j][0], dp[(i - 1) & 1][j][1]);
			dp[i & 1][j][1] = max(dp[(i - 1) & 1][j - 1][0], dp[(i - 1) & 1][j - 1][1] + U[i]);
		}
	}
	ans = max(ans, dp[N & 1][B][1]);
	cout << ans << endl;
}

int main()
{
	IOS;
	cin >> N >> B;
	for (int i = 1; i <= N; i++)
		cin >> U[i];
	solve();

	return 0;
}

posted @ 2022-03-02 20:07  Prgl  阅读(28)  评论(0)    收藏  举报