SP283 NAPTIME - Naptime
SP283 NAPTIME - Naptime
题意:
在某个星球上,一天由N小时构成。我们称0-1点为第一个小时,1-2点为第二个小时,以此类推。在第i个小时睡觉能恢复Ui点体力。在这座星球上住着一头牛,它每天要休息B个小时,它休息的这B个小时可以不连续,可以分成若干段,但是在每一段的第一个小时不能恢复体力,从第二个小时开始才可以恢复体力。 为了身体健康,这头牛希望遵循生物钟,每天采用相同的睡觉计划。另外,因为时间是连续的,每天的第N个小时与下一天的第一个小时是相连的,这头牛只需要在N个小时内休息B个小时就够了。 请你给这头牛安排一个任务计划,使得它每天恢复的体力最多。
输入格式: 第一行一个整数T表示有T组测试数据 对于每一组测试数据,第一行为两个整数N与B,接下来N行每行一个整数Ui。(2 <= B < N <= 3830 , 0 <= Ui <= 200000)
输出格式: 对于每组输入数据,对应一行输出一个整数,表示答案。(注意:两组输出之间没有空行)
我们可以发现一些很显然的性质:如果第一小时的体力值能够恢复,当且仅当第n小时和第一小时都在睡觉,然而我们并不确定第n小时究竟是不是睡觉,所以就不知道应该怎样给第一天初始值了,但是如果我们将这一限制去除,那么无论第n小时在不在睡觉第一小时都不会回复体力值,这样就可以进行第一次的dp,但是样就会出现一个问题,如果第一小时和第n小时都在睡觉,那么就会少U[1]点体力值,这样的话我们就可以强制令第一小时和第n小时都在睡觉,再进行一次dp并且把U[1]加进去,两次dp取最大值,就是答案了。
1 #include<iostream> 2 #include<string> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<stack> 7 #include<queue> 8 #define maxn 4005 9 using namespace std; 10 11 inline int read() 12 { 13 char c=getchar(); 14 int x=1,res=0; 15 while(c<'0'||c>'9') 16 { 17 if(c=='-') 18 x=-1; 19 c=getchar(); 20 } 21 while(c>='0'&&c<='9') 22 { 23 res=res*10+(c-'0'); 24 c=getchar(); 25 } 26 return x*res; 27 } 28 29 int t,n,m,ans; 30 int a[maxn]; 31 int f[maxn][maxn][2],dp[maxn][maxn][2]; 32 33 int main() 34 { 35 t=read(); 36 while(t--) 37 { 38 ans=0; 39 n=read();m=read(); 40 for(int i=1;i<=n;i++) 41 { 42 a[i]=read(); 43 } 44 memset(f,-0x3f,sizeof(f)); 45 f[1][0][0]=0;f[1][1][1]=0; 46 for(int i=2;i<=n;i++) 47 { 48 for(int j=0;j<=m;j++) 49 { 50 if(j>0) f[i][j][1]=max(f[i-1][j-1][0],f[i-1][j-1][1]+a[i]); 51 f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]); 52 } 53 } 54 ans=max(f[n][m][1],f[n][m][0]); 55 memset(f,-0x3f,sizeof(f)); 56 f[1][1][1]=a[1]; 57 for(int i=2;i<=n;i++) 58 { 59 for(int j=0;j<=m;j++) 60 { 61 if(j>0) f[i][j][1]=max(f[i-1][j-1][0],f[i-1][j-1][1]+a[i]); 62 f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]); 63 } 64 } 65 ans=max(ans,f[n][m][1]); 66 printf("%d\n",ans); 67 } 68 return 0; 69 }