Codeforces 1442D Sum

https://codeforces.ml/contest/1442/problem/D

题意:给 \(n\) 个不减的正数数组,每个数组只能从头开始取,求任取 \(k\) 个数和的最大值。 \(1 \le n, k \le 3\,000\)

题解:

显然没有递减的条件的话就是个条件依赖背包问题,然后 \(O(n^2k)\) 就写完了。

然后发现有这个条件之后,最后的答案中一定最多有一个序列是没有取满的,可以反证法证明。

对于序列 i 和 j 如果都没有取满,\(next_i\) 表示 i 序列中下一个数,\(next_j\) 表示 j 序列中下一个数,则 \(now_j \le next_i\)\(now_i \le next_j\) 都成立,显然不是最优解。

然后就想到把同一个组看成一个物品添加到背包中,维护一下前后缀的背包值然后合并,求中间去掉一个的答案,但是由于背包合并的复杂度是 \(O(k^2)\) 显然不成立。

有个科技叫:"knapsack of all elements but one"

然后就分治一下,在分治的最底层(只有一个元素时)求解,前面的就把组内的元素看成一个物品添加至背包。

算一下复杂度:分治中某个地方有 len 个数组,则需要把 len 个物品添加进背包,复杂度为 $ len*k $ 由于分治树中有 logn 层,每层的 len 和都是 n,所以总复杂度就是 \(O(nklogn)\)

总体来说就是为了避免背包中删除一个物品这种过于复杂的操作。

/*================================================================
*
*   创 建 者: badcw
*   创建日期: 2021/3/11 8:44 下午
*
================================================================*/
#include <bits/stdc++.h>

#define VI vector<int>
#define ll long long
#define dbg1(x) cerr<<#x<<"="<<(x)<<" "
#define dbg2(x) cerr<<#x<<"="<<(x)<<"\n"
using namespace std;

namespace IO {
    template<class T>
    void _R(T &x) { cin >> x; }
    void _R(int &x) { scanf("%d", &x); }
    void _R(ll &x) { scanf("%lld", &x); }
    void _R(double &x) { scanf("%lf", &x); }
    void _R(char &x) { x = getchar(); }
    void _R(char *x) { scanf("%s", x); }
    void R() {}
    template<class T, class... U>
    void R(T &head, U &... tail) {_R(head),R(tail...);}
    template<class T>
    void _W(const T &x) { cout << x; }
    void _W(const int &x) { printf("%d", x); }
    void _W(const ll &x) { printf("%lld", x); }
    void _W(const double &x) { printf("%.16f", x); }
    void _W(const char &x) { putchar(x); }
    void _W(const char *x) { printf("%s", x); }
    template<class T, class U>
    void _W(const pair<T, U> &x) {_W(x.first),putchar(' '),_W(x.second);}
    template<class T>
    void _W(const vector<T> &x) { for (auto i = x.begin(); i != x.end(); _W(*i++)) if (i != x.cbegin()) putchar(' '); }
    void W() {}
    template<class T, class... U>
    void W(const T &head, const U &... tail) {_W(head),putchar(sizeof...(tail) ? ' ' : '\n'),W(tail...);}
}
using namespace IO;


const int maxn = 3005;
const int mod = 1e9+7;

ll qp(ll a, ll n) {
    ll res = 1;
    n %= mod - 1;
    if (n < 0) n += mod - 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

ll qp(ll a, ll n, int mod) {
    ll res = 1;
    n %= mod - 1;
    if (n < 0) n += mod - 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

vector<VI> item;
int n, k;
ll f[maxn];
pair<int, ll> a[maxn];
ll res;

inline void dfs(int l, int r) {
    if (l > r) return;
    if (l == r) {
        ll sum = 0;
        for (int i = 0; i < (int)item[l].size(); ++i) {
            sum += item[l][i];
            res = max(res, f[k - i - 1] + sum);
        }
    } else {
        ll tmp[maxn]; for (int i = 0; i <= k; ++i) tmp[i] = f[i];
        int m = l + r >> 1;
        for (int i = m + 1; i <= r; ++i) {
            for (int j = k; j >= a[i].first; --j) {
                f[j] = max(f[j], f[j - a[i].first] + a[i].second);
            }
        }
        dfs(l, m);
        for (int i = 0; i <= k; ++i) f[i] = tmp[i];
        for (int i = l; i <= m; ++i) {
            for (int j = k; j >= a[i].first; --j) {
                f[j] = max(f[j], f[j - a[i].first] + a[i].second);
            }
        }
        dfs(m + 1, r);
    }
}

int main(int argc, char* argv[]) {
    R(n, k); item.resize(n + 1);
    for (int i = 1; i <= n; ++i) {
        ll sum = 0;
        int sz; R(sz);
        item[i].resize(sz);
        for (int j = 0; j < sz; ++j) {
            R(item[i][j]);
            sum += item[i][j];
        }
        if ((int)item[i].size() > k) item[i].resize(k);
        a[i] = {sz, sum};
    }
    dfs(1, n);
    W(res);
    return 0;
}
posted @ 2021-03-11 21:38  badcw  阅读(73)  评论(0编辑  收藏  举报