Loading

[USACO22DEC] Bribing Friends G

题意

给定 \(N\) 个物品,第 \(i\) 个物品的价值为 \(P_i\),重量为 \(C_i\),第 \(i\) 个物品每花费 \(X_i\) 元,可使其重量减 \(1\)。重量不能减少至负数。现在有 \(A\) 容量的背包和 \(B\) 元,试求能够装下的物品的最大的价值。

数据范围:\(1\le N,P_i,C_i,X_i,A,B\le 2\times 10^3\)

思路

容易发现(我没发现),由于都是使重量减 \(1\),那肯定花费越小的越好,即使劲用 \(X_i\) 小的,用完再用次小的,以此类推。

那么,所有选择物品中,按 \(X_i\) 从小到大排序,前缀必然是全部花费 \(X_i\) 元,使得重量为 \(0\),花费 \(C_iX_i\) 元;后缀必然是使用 \(C_i\) 的重量装填。中间一个物品使用一部分。故,预处理前缀、预处理后缀、中间的物品暴力枚举即可。

时间复杂度 \(O(N\max(A,B))\)

Code

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2005;

int N, A, B;
struct info {
    int P, C, X;
    bool operator< (const info &T)const {
        return X < T.X;
    }
}F[maxn];
int f[maxn][maxn], g[maxn][maxn];

int main() {
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);

    cin >> N >> A >> B;
    for (int i = 1; i <= N; i ++)
        cin >> F[i].P >> F[i].C >> F[i].X;
    sort(F + 1, F + 1 + N);

    memset(f, -0x3f, sizeof f);
    for (int i = 0; i <= B; i ++)
        f[0][i] = 0;
    for (int i = 1; i <= N; i ++)
        for (int j = 0; j <= B; j ++) {
            f[i][j] = f[i - 1][j];
            if (j >= F[i].C * F[i].X)
                f[i][j] = max(f[i - 1][j - F[i].C * F[i].X] + F[i].P, f[i][j]);
        }

    memset(g, -0x3f, sizeof g);
    for (int i = 0; i <= A; i ++) g[N + 1][i] = 0;
    for (int i = N; i >= 1; i --)
        for (int j = 0; j <= A; j ++) {
            g[i][j] = g[i + 1][j];
            if (j >= F[i].C)
                g[i][j] = max(g[i + 1][j - F[i].C] + F[i].P, g[i][j]);
        }

    int res = -(1 << 30);
    for (int i = 1; i <= N; i ++)
        for (int j = 0; j <= F[i].C; j ++) {
            int _A = j, _B = (F[i].C - j) * F[i].X;
            if (_B > B) continue;
            res = max(res, f[i - 1][B - _B] + g[i + 1][A - _A] + F[i].P);
        }

    cout << res << endl;
    
    return 0;
}
posted @ 2025-04-18 10:01  Pigsyy  阅读(15)  评论(0)    收藏  举报