这道题开始时觉得dp只能n^3的做法,只考虑贪心,但贪心也没选对方法,只能说这种贪心还是第一次见,涨芝士了。

首先如果是只有两个数的话,那dp都不用了,直接贪心。

这里先说一下只有两个数时,

这里用到的贪心是,对于每一个pick,先把(b-a)差值更大的前b个选了,然后剩下a个都选a,

我们只考虑选b的结果,对于一个pick,如果b>a那么我们选b是赚的,反之我们选b亏一些,所以选a就可以了。但这样并不完全对

如果 a=2,b=1;

 其实你先选了第一组会亏,可以这样理解因为我们总要选b个b,选a个a,如果b-a>0那么我们尽可能选差值更大的,这样我们选b的收益更大,然后我们选b-a差值更小的,也就是a-b差值更大的,这样我们的选a对于b的亏损更少,但如果b-a>0的数不够b个,我们还选b就可以了,这样还是可以保证b的亏损是最小的,所以就可以把排序的便准设为 

struct node{

    int a,b,c;
    friend operator<(node x,node y){
        return x.b-x.a>y.b-y.a;/将差值更大的排在前面
    }

}

然后就考虑c,其实我们只用把dp设为dp[i][j],表示前i个数,c选了j个,然后第一层循环表示枚举每一个3pick,第二层循环表示枚举每一种可能的j值,对于每一种情况,如果j>0那说明我们可以选c,c是不受限制的,只要可以就一直更新,如果i-j<=b 那我们就都选b,否则就选a

然后这个dp的初始化还是有些奇妙,我们不能把他们设为0,比如说如果我们要构造成dp[3][4],然后我们要选a,那说明我们要用dp[2[3],但是dp[2][3]可能不存在,所以我们只把j=0的所有情况都设为0,其他的设为负无穷

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
typedef long long ll;
const int maxn = 5e3+10;
struct node{

    int a,b,c;
    friend operator<(node x,node y){
        return x.b-x.a>y.b-y.a;
    }

}r[maxn];
int n,a,b,c;
ll dp[maxn][maxn];
int main()
{
    scanf("%d %d %d %d",&n,&a,&b,&c);
    for(int i = 1; i <= n ; i++){
        scanf("%d %d %d",&r[i].a,&r[i].b,&r[i].c);
    }
    sort(r+1,r+n+1);
    for(int i = 0; i <= n ; i++){
        for(int j = 1; j <= c; j++){
            dp[i][j]=-1e18;
        }
    }
    for(int i = 1 ; i <= n ; i++){
        for(int j = 0 ; j <= min(c,i); j++){
            if(j) dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1ll*r[i].c);
            if(i-j<=b) dp[i][j]=max(dp[i][j],dp[i-1][j]+1ll*r[i].b);
            else       dp[i][j]=max(dp[i][j],dp[i-1][j]+1ll*r[i].a);
        }
    }printf("%lld",dp[n][c]);
    return 0;
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐