训练赛后补题 03

2020-06-29 个人训练赛后补题

这一题当时觉得看起来好像比较好理解,然后在草稿纸上演算了半天没想到法子,都有bug

开始补题:

时间复杂度爆表得我无可奈何去查了题解:

dp:

令dp[i][j]表示在【1, i】内消灭j段野火炮所获得的最大收益,sum[i]表示前缀和

那么很容易得出dp[i][j] = max( dp[i - 1][j], dp[i - m][j - 1] + sum[i] – sum[i – m])

大意就是:

如果选择了第i个位置作为一段中的一员, 那么就要在前面的[1, i- m]中选择j – 1段。   

如果没选第i个位置,就在[1, i – m]中选择j段

行吧,我太菜了QAQ

最讨厌就是答案解析上的“略”和“由此可得/很容易就能得出”了

我菜死了QAQ

 

努力思考了一下题解,意思应该是最大收益要么是前i个中霍霍k段的最大效益,要么是霍霍末m个与前i-m个中霍霍k-1段的最大效益。也就是说从头到尾不必考虑所有状态,只用考虑从最小值到 i,j 时的最大收益,递推完事。不过我怕爆栈,还是用循环吧。

 

害,硬生生把n^3降到n^2,我怎么就没想到呢。

铁憨憨如我赛时压根没想到用dp。

下面贴代码:

 1 #pragma warning (disable:4996)
 2 #include <iostream>
 3 #include<algorithm>
 4 #include<stdio.h>
 5 #include<math.h>
 6 #include<string.h>
 7 #include<string>
 8 #define MAX1 100005            /*1e5 + 5*/
 9 #define MAX2 1000000005        /*le9 + 5*/
10 #define MAX3 200005            /*1e5 + 5*/
11 #define MAX4 5005            /*5e4 + 5*/
12 #define T2 27
13 #define T3 18
14 using namespace std;
15 typedef long long int ll;
16 #define MOL 998244353
17 
18 
19 ll dp[MAX4][MAX4] = { 0 };
20 int main() {
21     ll n, m, k, p[MAX4] = { 0 }, i, j;
22     while (scanf("%lld %lld %lld", &n, &m, &k) != EOF) {
23         ll m_sum[MAX4] = { 0 };
24         for (i = 1; i <= n; ++i) {
25             scanf("%lld", &p[i]);
26             m_sum[i] = m_sum[i - 1] + p[i];        //前缀和
27         }                                        //从1起,0无意义
28         ll x1 ,x2;
29         for (i = 0; i < m; ++i) {
30             dp[i][0] = 0;
31             dp[i][1] = 0;
32         }
33         for (i = m; i <= n; ++i) {                //[1,i]i最小为m,最大n
34             for (j = 1; j <= k; ++j) {            //j最小为1,最大为k,所求为k
35                 x1 = dp[i - 1][j];
36                 x2 = dp[i - m][j - 1] + m_sum[i] - m_sum[i - m];
37                 dp[i][j] = x1 < x2 ? x2 : x1;
38             }
39         }
40         printf("%lld\n", dp[n][k]);
41     }
42     return 0;
43 }

 

posted @ 2020-06-30 15:47  听说福建人很好吃  阅读(89)  评论(0)    收藏  举报