1. 程式人生 > 其它 >選元素(線性DP)

選元素(線性DP)

題意

給定一個長度為 \(n\) 的整數序列 \(a_1, a_2, \dots, a_n\)

請你從中挑選 \(x\) 個元素,要求:

  • 原序列中的每一個長度為 \(k\) 的連續子序列都至少包含一個被選中的元素。

輸出最大可能和。

資料範圍

\(1 \leq n, k, x \leq 200\)

思路

考慮使用DP。令\(f_{i, j}\)表示最後一個選取的元素的下標是\(i\),總共選取了\(j\)個元素的最大和。則:

\(f_{i, j} = \max\limits_{i - k \leq t < i}(f_{i, j}, f_{t, j - 1})\)

程式碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;

const int N = 210;

int n, kk, x;
ll a[N];
ll f[N][N];

int main()
{
    scanf("%d%d%d", &n, &kk, &x);
    for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
    memset(f, -0x3f, sizeof f);
    f[0][0] = 0;
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j <= x; j ++) {
            for(int k = max(0, i - kk); k < i; k ++) {
                f[i][j] = max(f[i][j], f[k][j - 1] + a[i]);
            }
        }
    }
    ll ans = -1;
    for(int i = n - kk + 1; i <= n; i ++) ans = max(f[i][x], ans);
    printf("%lld\n", ans);
    return 0;
}