HDU-3905 Sleeping

来源:互联网 发布:好家伙 盗亦有道 知乎 编辑:程序博客网 时间:2024/06/11 13:19

1.题面

http://acm.hdu.edu.cn/showproblem.php?pid=3905

2.题目大意

一节课N分钟,在第i分钟听课会获得的收益是a[i],同时每次听课至少要听L分钟。ZZZ要在保证课上至少睡M分钟的前提下获得最大的收益,求这个最大收益是多少?

3.解题思路

很容易想到用dp[i][j]来表示在第i分钟的时候ZZZ已经睡了j分钟所能得到的最大收益,这个状态会受到两种状态影响:

        1.dp[i][j] = dp[i-1][j-1];如果ZZZ在这一分钟选择睡觉。

        2.dp[i][j] = max(dp[k][j] + pointSum(k+1,i)) k∈[0,i-L]。可以往这个状态转移的前提是k能够取到。

上面第一种转移方式没有问题,但第二种转移方式如果枚举所有K的值会产生O(n^3)的复杂度导致超时。优化需要用到下面这条关系:

       ① dp[i][j] = max(dp[k][j] + pointSum(k+1,i))                    k∈[0,i-L]

                    = max(dp[k][j] + pointSum(k+1,i-1) + a[i] )     k∈[0,i-L]

                    = max(dp[k][j] + pointSum(k+1,i-1))+a[i];       k∈[0,i-L]

       ②dp[i-1][j] = max(dp[k][j] + pointSum(k+1,i-1))                    k∈[0,i-L-1]

上面两个状态很像,除了最后相差一个a[i]以外,前面由于k的取值范围的关系,其实还相差了一个k=i-L的情况,然后上面的dp[i][j]其实不是真正的dp[i][j],因为ZZZ在这一分钟睡觉的情况没有计算进去。

所以我们不妨先把上面的dp[i][j]成为tmp_dp[i][j]。

从上述关系式中,我们可以看到在我们拥有了tmp_dp[i-1][j]后,我们可以通过一步比较就获得tmp_dp[i][j]的大小,也就是说第二种状态转移中还隐藏了另一个状态转移。详见代码。

4.解题代码

/*****************************************************************    > File Name: tmp.cpp    > Author: Uncle_Sugar    > Mail: uncle_sugar@qq.com    > Created Time: 2016年03月12日 星期六 20时54分08秒*****************************************************************/# include <cstdio># include <cstring># include <cmath># include <cstdlib># include <climits># include <iostream># include <iomanip># include <set># include <map># include <vector># include <stack># include <queue># include <algorithm>using namespace std;# ifndef ONLINE_JUDGE struct DesktopIO{DesktopIO(){freopen("//home//unclesugar//in.txt","r",stdin);freopen("//home//unclesugar//out.txt","w",stdout);}}DIO;# endifconst int debug = 1;const int size  = 1000 + 10; const int INF = INT_MAX>>1;typedef long long ll;int point[size],psum[size];int dp[size][size];int tmp_dp[size][size];int main(){std::ios::sync_with_stdio(false);cin.tie(0);int i,j,k;int n,m,l;while (cin >> n >> m >> l){for (i=0;i<=n;i++)for (j=0;j<=m;j++){dp[i][j] = tmp_dp[i][j] = -INF;}for (i=1;i<=n;i++){cin >> point[i];psum[i] = psum[i-1] + point[i];}dp[0][0] = 0;int ans = 0;for (i=1;i<=n;i++){for (j=0;j<=i&&j<=m;j++){if (j!=0)dp[i][j] = max(dp[i][j],dp[i-1][j-1]);if (i==l+j)tmp_dp[i][j] = psum[i] - psum[i-l];else if (i>l+j){tmp_dp[i][j] = max(tmp_dp[i-1][j] + point[i],dp[i-l][j] + psum[i] - psum[i-l]);}dp[i][j] = max(dp[i][j],tmp_dp[i][j]);if (j==m)ans  = max(ans,dp[i][j]);}}cout << ans << '\n';}return 0;}


0 0
原创粉丝点击