B. 小 A 的卡牌游戏 题解(贪心优化dp)
题目链接
有一个显然的 \(O(n^3)\)dp,无法通过此题。
考虑如果只有两类卡组 a 和 b ,可以将每次 “3pick” 按 b − a 排序后贪心地先选择其中一类,再选另一类。
基于这个贪心,我们考虑对另一类卡组进行 dp。f(i, j) 表示前 i 次 “3pick” 中,有 j
次选择了第三类;没有选第三类的一定是根据前面的贪心选择优先选其中一类,而再选另一类。
复杂度:\(O(n^2)\)
主要是要考虑到贪心的方面去写来优化dp
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=5e3+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int num[4];
int n;
ll ans=0;
ll dp[maxn][maxn];
struct node{
int a,b,c;
}e[maxn];
bool cmp(node x,node y){
return x.b-x.a>y.b-y.a;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>num[1]>>num[2]>>num[3];
for(int i=1;i<=n;i++){
cin>>e[i].a>>e[i].b>>e[i].c;
}
sort(e+1,e+1+n,cmp);
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
dp[i][j]=-inf;
}
}
dp[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=min(i,num[3]);j++){
if(j!=0){// 选c
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+e[i].c);
}
if(i-j<=num[2]){ //选b
dp[i][j]=max(dp[i][j],dp[i-1][j]+e[i].b);
}else{
dp[i][j]=max(dp[i][j],dp[i-1][j]+e[i].a);
}
}
}
cout<<dp[n][num[3]]<<'\n';
return 0;
}
不摆烂了,写题