首页 > 其他分享 >P6240

P6240

时间:2024-09-22 21:49:06浏览次数:1  
标签:LG int P6240 rep Value RF RG

题面稍微有一点不一样。

Statement

给 \(n\) 个物品,每个物品有价值 \(v_i\)、体积 \(w_i\)。

\(q\) 次询问,问考虑 \([L..R]\) 区间的物品,用容量为 \(m\) 的背包最多能装多少价值的物品,有多少种方案,每个物品只能被装一次。

\(n\le 2\cdot 10^4, q\le 10^5, w_i,m_i\le 500, v_i\le 10^6\).

Solution

离线下来猫树分治。每次对于分治区间 \([l..r]\),回答所有跨过 \(mid\) 的询问。

如果我们知道两个“至多”的 01 背包数组,就可以 \(O(m)\) 每次回答。

如何处理出两个“至多”的 01 背包数组呢?在处理“恰好”的数组的同时对前一个取 max。

Code

不保证输入输出格式正确。

// 没卡常
#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = (j); i <= (k); ++i)
#define reo(i, j, k) for (int i = (j); i >= (k); --i)
typedef long long ll;
const int N = 20010, Q = 100010, M = 510, P = 998244353, INF = 1e9;
int n, m, q;
struct Item {
    int v, w;
} a[N];
struct Queries {
    int l, r, m, id;
} qq[Q];
pair<int, int> ans[Q];

int LF[N][M], LG[N][M], RF[N][M], RG[N][M];
int Max[N][M], MxSumG[N][M];

void Solve(int l, int r, vector<int> & vec) {
    if (l > r) return;
    if (l == r) {
        for (int id : vec) {
            auto & now = qq[id];
            if (now.m < a[l].w) ans[now.id] = make_pair(0, 0);
            else ans[now.id] = make_pair(a[l].v, 1);
        }
        return;
    }
    int mid = (l + r) >> 1;

    rep(i, l - 1, r + 1) {
        rep(j, 0, m) LF[i][j] = RF[i][j] = -INF, LG[i][j] = RG[i][j] = 0;
        LF[i][0] = RF[i][0] = 0, LG[i][0] = RG[i][0] = 1;
    }
    reo(i, mid, l) {
        rep(j, 0, m) {
            LF[i][j] = LF[i + 1][j];
            LG[i][j] = LG[i + 1][j];
        }
        reo(j, m, a[i].w) {
            int Value = LF[i][j - a[i].w] + a[i].v;
            if (Value > LF[i][j]) LF[i][j] = Value, LG[i][j] = LG[i][j - a[i].w];
            else if (Value == LF[i][j]) LG[i][j] = (LG[i][j] + LG[i][j - a[i].w]) % P;
        }
    }
    rep(i, mid + 1, r) {
        rep(j, 0, m) {
            RF[i][j] = RF[i - 1][j];
            RG[i][j] = RG[i - 1][j];
        }
        reo(j, m, a[i].w) {
            int Value = RF[i][j - a[i].w] + a[i].v;
            if (Value > RF[i][j]) RF[i][j] = Value, RG[i][j] = RG[i][j - a[i].w];
            else if (Value == RF[i][j]) RG[i][j] = (RG[i][j] + RG[i][j - a[i].w]) % P;
        }
    }
    rep(i, mid + 1, r) {
        Max[i][0] = RF[i][0], MxSumG[i][0] = RG[i][0];
        rep(j, 1, m) {
            Max[i][j] = Max[i][j - 1], MxSumG[i][j] = MxSumG[i][j - 1];
            if (RF[i][j] > Max[i][j]) Max[i][j] = RF[i][j], MxSumG[i][j] = RG[i][j];
            else if (RF[i][j] == Max[i][j]) MxSumG[i][j] = (MxSumG[i][j] + RG[i][j]) % P;
        }
    }

    vector<int> Left, Right;
    for (int id : vec) {
        auto & now = qq[id];
        if (now.l <= mid && mid < now.r) {
            int F = 0, G = 0;
            rep(i, 0, now.m) {
                int Value = LF[now.l][i] + Max[now.r][now.m - i];
                int nowG = 1ll * LG[now.l][i] * MxSumG[now.r][now.m - i] % P;
                if (Value > F) F = Value, G = nowG;
                else if (Value == F) G = (G + nowG) % P;
            }
            ans[now.id] = make_pair(F, G);
        } else if (now.r <= mid) {
            Left.push_back(id);
        } else if (mid < now.l) {
            Right.push_back(id);
        } else {
            assert(0);
        }
    }
    Solve(l, mid, Left), Solve(mid + 1, r, Right);
}

int main() {
    freopen("knapsack.in", "r", stdin), freopen("knapsack.out", "w", stdout);
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cin >> n;
    rep(i, 1, n) {
        cin >> a[i].v >> a[i].w;
    }
    cin >> q;
    rep(i, 1, q) {
        cin >> qq[i].l >> qq[i].r >> qq[i].m, qq[i].id = i;
        m = max(m, qq[i].m);
    }
    vector<int> vec;
    rep(i, 1, q) vec.push_back(i);
    Solve(1, n, vec);
    rep(i, 1, q) {
        int p = ans[i].first, q = ans[i].second;
        if (!p) cout << "0 0\n";
        else cout << p << ' ' << q << '\n';
    }
    return 0;
}

标签:LG,int,P6240,rep,Value,RF,RG
From: https://www.cnblogs.com/laijinyi/p/18425949

相关文章