训练赛后补题 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 }

浙公网安备 33010602011771号