SPOJ NAPTIME Naptime

https://www.spoj.com/problems/NAPTIME/en/

题目

一天有n小时,有头牛,每n小时只能在床上呆B小时(不一定连续),在床上的第一小时还不能睡着,要第二小时开始才睡着,如果在第i小时的时候是睡着的,她就可以获得$U_i$点精力,先选择连续的n小时,然后在这n小时中选择不一定连续的B小时使她获得的精力最大,求最大值。

3 <= N <= 3,830

题解

第一想法:拆成环,然后dp[a][b][c][2]表示从第a小时开始,现在是b小时,在床上呆了c小时,这时是否在床上,然后就肯定超时了

其实有另外的做法

直接在一天内dp,区别只是“最后一小时处于睡眠状态并且第一小时获得了精力”的真假,那么可以进行两次背包

dp[i][j][0/1]表示现在是i,在床上呆了c小时,这时是否在床上

那么很容易写出转移

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cassert>
#define REP(i,a,b) for(register int i=(a); i<(b); i++)
#define REPE(i,a,b) for(register int i=(a); i<=(b); i++)
#define PERE(i,a,b) for(register int i=(a); i>=(b); i--)
using namespace std;
#define MAXN 3837
int u[MAXN];
int dp[2][MAXN][2]; //now B
int main() {
	int t; scanf("%d", &t);
	while(0<t--) {
		int n,b; scanf("%d%d", &n, &b);
		REP(i,0,n) {
			scanf("%d", &u[i]);
		}
		memset(dp,-0x3f,sizeof dp);
		dp[0][0][0]=0; dp[0][1][1]=0;
		int now=0;
		REP(i,1,n) {
			now^=1;
			REPE(j,0,b) {
				if(j) dp[now][j][1]=max(dp[now^1][j-1][0],dp[now^1][j-1][1]+u[i]);
				dp[now][j][0]=max(dp[now^1][j][0],dp[now^1][j][1]);
			}
		}
		int ans=max(dp[now][b][0],dp[now][b][1]);
		now=0;
		memset(dp,-0x3f,sizeof dp);
		dp[0][1][1]=u[0];
		REP(i,1,n) {
			now^=1;
			REPE(j,0,b) {
				if(j) dp[now][j][1]=max(dp[now^1][j-1][0],dp[now^1][j-1][1]+u[i]);
				dp[now][j][0]=max(dp[now^1][j][0],dp[now^1][j][1]);
			}
		}
		ans = max(ans, dp[now][b][1]);
		printf("%d\n", ans);
	}
}

猜你喜欢

转载自www.cnblogs.com/sahdsg/p/12483587.html
今日推荐