NC207751 牛牛的旅游纪念品

题目链接

题目

题目描述

牛牛在牛市的旅游纪念商店里面挑花了眼,于是简单粗暴的牛牛决定——买最受欢迎的就好了。

但是牛牛的背包有限,他只能在商店的n个物品里面带m个回去,不然就装不下了。

并且牛牛希望买到的纪念品不要太相似,所以导购小姐姐帮助牛牛把纪念品全部排成了一行,牛牛只需要让选出来要买的m个物品中任意两个的位置差都大于等于k就行了。

现在告诉你这n个物品排成一行之后的受欢迎程度(可能是负数),求牛牛带回去的m个物品的最大欢迎度之和。

输入描述

第一行三个数n,m,k 接下来一行,有n个整数,是n个物品按顺序的受欢迎程度。

输出描述

输出一个数为题目所求的最大和

示例1

输入

4 2 2
2 4 -6 1

输出

5

说明

\(n\leq10000,m\leq100,m\leq n\) ,答案保证在int范围内,保证按照题目要求一定能取到m个物品

题解

知识点:背包dp。

一个01背包变形,第 \(i\) 个物品要从 \(i-k\) 转移。因此如 \(dp[i][0]\) 的初始化要手写而不能递推下去了。有转移方程:

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

因为 \(i < k\) 时,也是能选自己的因此用一个 \(\max\) 限制一下。

时间复杂度 \(O(nm)\)

空间复杂度 \(O(nm)\)

代码

#include <bits/stdc++.h>

using namespace std;

int a[10007], dp[10007][107];

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m, k;
    cin >> n >> m >> k;
    for (int i = 1;i <= n;i++) cin >> a[i];
    memset(dp, -0x3f, sizeof(dp));
    dp[0][0] = 0;
    for (int i = 1;i <= n;i++) {
        dp[i][0] = 0;
        for (int j = 1;j <= m;j++) {
            dp[i][j] = max(dp[max(0, i - k)][j - 1] + a[i], dp[i - 1][j]);
            ///i<k时,还有j=1时候能选自己即,dp[0][0] + a[i]所以不能if掉
        }
    }
    cout << dp[n][m] << '\n';
    return 0;
}
posted @ 2022-08-12 17:41  空白菌  阅读(55)  评论(0编辑  收藏  举报