题目链接:Click here~~
题意:
有一个人有严格的生物钟,他一般醒的时间长度为 t,可延长 l 的时间,然后立即就会睡 k+l,且醒的时间不够 t 不能睡。
给 n 个节目的播出时间表,每个节目有个 val 值,问如何能使总 val 值最大。
解题思路:
状态不太好想。
dp[i][j] 表示总时间为 i ,已经醒了 j 分钟的状态。
然后对于每个状态,最多只有三种转移,看节目 or 睡觉 or 啥也不干。
照着这样一直向后递推就行了。注意最后的 ans 不是 max{ dp[i][j] } ,而是 max{ dp[i][0] }。
细节:i 只循环到 10000 是错误的,因为有可能他到 10000 这个时间点的时候刚醒,所以要循环到 10120。从而最后的 i 有可能达到 10240。
#include <vector>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 1e4 + 5;
int dp[N+250][125];
vector< pair<int,int> > events[N];
inline void check_max(int &a,int b){
a = a > b ? a : b;
}
int main()
{
int T,n,awake,sleep,delay;
scanf("%d",&T);
while(T--)
{
for(int i=0;i<=10000;i++)
events[i].clear();
scanf("%d%d%d%d",&n,&awake,&sleep,&delay);
for(int i=0;i<n;i++)
{
int s,e,v;
scanf("%d%d%d",&s,&e,&v);
events[s].push_back(make_pair(e,v));
}
memset(dp,-127,sizeof(dp));
const int inf = dp[0][0];
dp[0][0] = 0;
for(int i=0;i<=10125;i++)
for(int j=0;j<=awake+delay;j++){
if(dp[i][j] == inf)
continue;
check_max(dp[i+1][j+1],dp[i][j]);
for(int k=0;k<(int)events[i].size();k++){
int endt = events[i][k].first;
int val = events[i][k].second;
int jj = j + endt - i;
if(jj > awake + delay)
continue;
check_max(dp[endt][jj],dp[i][j]+val);
}
if(j >= awake)
check_max(dp[i+sleep+j-awake][0],dp[i][j]-(j-awake)*(j-awake));
}
int ans = 0;
for(int i=0;i<N+250;i++)
ans = max(ans,dp[i][0]);
printf("%d\n",ans);
}
return 0;
}