标签:wrap detail pac open evel help ble ever 滚动
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 3649 | Accepted: 1350 |
Description
Input
Output
Sample Input
5 3 2 0 3 1 4
Sample Output
6
Hint
Source
一天有n个时间,有一只牛希望一天可以休息睡小时。如果牛在第i时刻已经熟睡,他可以得到ui的休息。但是如果他在i时刚刚入睡,他不能得到休息。牛可以从前一天晚上睡到第二天。睡觉时间也不一定连续。问如何安排睡觉时间,可以使牛得到的休息最大。
参照wyboooo的题解。
如果牛休息的时间不能从前一天跨越到第二天的话,就是一道典型的线性DP
我们先假设不能跨越,那么第1个小时一定得不到休息。用dp[i][j][0]和dp[i][j][1]分别表示,在第i时刻休息了j小时并且第i时刻在睡觉,和在第i时刻休息了j小时并且第i时刻不在睡觉的最大休息值。跑一遍DP,在dp[n][b][0], dp[n][b][1]中选择最优解。
这种假设的情况下,我们可以发现和题意原来的意思就差了第1个小时的时候。那么我们强制令第n个时刻和第1个时刻都在睡觉,也就是说第1个时刻可以得到休息值。再跑一遍DP,把dp[n][b][1]和之前的最优解比较取最优就是答案
本题的解法本质上是把问题拆成了两部分。这两部分合起来可以覆盖整个问题。无论是哪一部分,因为第n小时和第1小时之间的特殊关系被确定,我们就可以把环拆开,用线性DP计算。
时间复杂度\(O(nm)\)
卡着开空间的话,会使用58.706244MB,不会炸内存。但为什么不练一练滚动数组呢?
#include<iostream>
#include<cstring>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using std::max;
co int N=4e3;
int n,m,f[2][N][2],w[N],ans;
int main(){
// freopen(".in","r",stdin),freopen(".out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;++i) read(w[i]);
if(m==0) return puts("0"),0;
memset(f,0x80,sizeof f);
f[1&1][0][0]=0;
f[1&1][1][1]=0;
for(int i=2;i<=n;++i)
for(int j=0;j<=m;++j){
f[i&1][j][0]=max(f[(i-1)&1][j][0],f[(i-1)&1][j][1]);
if(j>=1) f[i&1][j][1]=max(f[(i-1)&1][j-1][0],f[(i-1)&1][j-1][1]+w[i]);
}
ans=max(f[n&1][m][1],f[n&1][m][0]);
memset(f,0x80,sizeof f);
f[1&1][1][1]=w[1];
for(int i=2;i<=n;++i)
for(int j=0;j<=m;++j){
f[i&1][j][0]=max(f[(i-1)&1][j][0],f[(i-1)&1][j][1]);
if(j>=1) f[i&1][j][1]=max(f[(i-1)&1][j-1][0],f[(i-1)&1][j-1][1]+w[i]);
}
ans=max(ans,f[n&1][m][1]);
return printf("%d\n",ans),0;
}
标签:wrap detail pac open evel help ble ever 滚动
原文地址:https://www.cnblogs.com/autoint/p/10666931.html