Solution - P8903 [USACO22DEC] Bribing Friends G

主观难度:【2】

挺合理的。应该说 \(\mathrm O(n^3)\) 部分分容易教坏选手吗。


\(\mathrm O(n^3)\) 是容易想到的,正解和这个也没有任何关系。

考虑对 \(x\) 排序,发现答案必定是前半段以甜筒支付,后半段以钱支付,中间有一个混合支付。这容易证明,因为同样的甜筒对于更前的牛能抵扣更多的钱。

于是顺着用甜筒 DP,倒着用钱 DP,枚举中间点即可。

假设所有数据同阶,得到复杂度 \(\mathrm O(n^2)\)

#include <bits/stdc++.h>
#define llong long long
#define N 2005
using namespace std;

#define bs (1<<20)
char buf[bs], *p1, *p2;
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,bs,stdin),p1==p2)?EOF:*p1++)
template<typename T>
inline void read(T& x){
    x = 0; int w = 1;
    char ch = gc();
    while(ch < '0' || ch > '9'){
        if(ch == '-') w = -w;
        ch = gc();
    }
    while(ch >= '0' && ch <= '9')
        x = (x<<3)+(x<<1)+(ch^48), ch = gc();
    x *= w;
}
template<typename T, typename ...Args>
inline void read(T& x, Args& ...y){
    return read(x), read(y...);
}

int n, a1, a2;
int dp1[N][N], dp2[N][N];
int ans;

struct Node{
    int v, w, k;
} a[N];

int main(){
    read(n, a1, a2);
    for(int i = 1; i <= n; ++i)
        read(a[i].v, a[i].w, a[i].k);
    sort(a+1, a+n+1, [&](Node o1, Node o2){return o1.k < o2.k;});
    for(int i = 1; i <= n; ++i){
        for(int j = a2; j >= 0; --j) dp1[i][j] = dp1[i-1][j];
        for(int j = a2; j >= a[i].w*a[i].k; --j)
            dp1[i][j] = max(dp1[i][j], dp1[i-1][j-a[i].w*a[i].k]+a[i].v);
    }
    for(int i = n; i >= 1; --i){
        for(int j = a1; j >= 0; --j) dp2[i][j] = dp2[i+1][j];
        for(int j = a1; j >= a[i].w; --j)
            dp2[i][j] = max(dp2[i][j], dp2[i+1][j-a[i].w]+a[i].v);
    }
    ans = max(dp1[n][a2], dp2[1][a1]);
    for(int i = 1; i <= n; ++i){
        ans = max(ans, dp1[i-1][a1]+dp2[i+1][a2]);
        for(int j = 0; j <= a[i].w && j*a[i].k <= a2; ++j)
            ans = max(ans, dp1[i-1][a2-j*a[i].k]+dp2[i+1][a1-(a[i].w-j)]+a[i].v);
    }
    printf("%d", ans);
    return 0;
}

posted @ 2026-03-19 19:50  Hootime  阅读(2)  评论(0)    收藏  举报