【洛谷P2034】选择数字

Description

【洛谷P2034】选择数字

给定一个序列,选择其中若干个数,但不能有超过k个连续的数字被选择。最大化选出的数字之和。

Solution

dp+单调队列

正难则反,考虑从序列中取出一些数,这些数两两之间的距离不超过k,最小化之和

那么定义$f[i]$表示前i个数,取出一些的最小和(保证第i个取),那么显然有状态转移方程

$$f[i]=\min\{f[j]\}+a[i]\quad (i-k-1\le j<i)$$

可以发现,对于每一个i,决策允许集合中的j都是连续的一段,并且当i增加时,决策允许集合会与之前的一部分重叠,而且转移是求出最值,所以用一个单调队列维护一下就好了、

时间复杂度为$O(n)$

Code

#include <bits/stdc++.h>
// check if it is judged online

namespace shl {
    typedef long long ll;
    inline int read() {
        int ret = 0, op = 1;
        char c = getchar();
        while (!isdigit(c)) {
            if (c == '-') op = -1;
            c = getchar();
        }
        while (isdigit(c)) {
            ret = ret * 10 + c - '0';
            c = getchar();
        }
        return ret * op;
    }
    int n, m;
    ll a[100010], sum, f[100010], que[100010], h = 1, t = 1, tot;
    int main() {
        n = read(), m = read();
        for (register int i = 1; i <= n; ++i) a[i] = read(), tot += a[i];
        for (register int i = 1; i <= n; ++i) {
            f[i] = f[que[h]] + a[i];
            while (h <= t && f[i] <= f[que[t]]) t--;
            que[++t] = i;
            while (h <= t && que[h] <= i - m - 1) h++;
        }
        ll ans = 0;
        for (register int i = n - m; i <= n; ++i) ans = std::max(ans, tot - f[i]);
        printf("%lld\n", ans);
        return 0;
    }
}
int main() {
#ifdef LOCAL
    freopen("textname.in", "r", stdin);
    freopen("textname.out", "w", stdout);
#endif
    shl::main();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/shl-blog/p/11520354.html