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;
}

浙公网安备 33010602011771号