动态规划专题 - 解题报告 - I

这个动态规划一开始看起来很反人类,因为竟然每一次的选择会影响到后面选择的代价什么的,这就和动态规划要求的无后效性相悖?!那么如何去除这个后效性的影响就是这题的精髓了。既然改变的是魅力值对代价的贡献,我们就从魅力值的处理开始观察。
我们发现如果把攻略每位女主角需要的魅力值大小从大到小排过序后,选择魅力值要求较高的一个作为上限,再选其他的女主角就不需要计算在魅力值上的氪金了,只用考虑好感度的花费和收益,意思是这样预处理后就变成了一个板板的01背包?
我们不断枚举不同的女孩为上限,开始01背包,但是复杂度变成了n3 ?难顶了。(不过好像糖哥一开始是就拿n3 爆过去的)
突然想到,我们不是排过序吗?按照排序后的顺序循环使后一项为结尾的答案就不会影响到前一项的答案的话不就已经满足我们的需要了吗?这只需要我们每一次循环结束更新一次ans即可。最后滚动数组优化背包,就过了。(倒是不优化我竟然没过,应该是写挂了)
带注释ac代码如下:

#include<bits/stdc++.h>
#define FOR(a, b, c) for(int a=b; a<=c; a++)
#define maxn 6005
#define maxm 55
#define hrdg 1000000007
#define inf 2147483647
#define llinf 9223372036854775807
#define ll long long
#define pi acos(-1.0)
#define ls p<<1
#define rs p<<1|1
using namespace std;

ll n, m, k, x, y, ans;
ll a, b, c, d;
ll dp[maxn];      //全员ll

inline ll read(){
    char c=getchar();long long x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

struct node
{
    ll val, cost, goal;
}girl[maxn];

bool cmp(node x, node y) {return x.goal > y.goal;}

int main()
{
    n = read(); m = read(); k = read();     //妹子个数,总钱数,基础魅力值
    x = read(); y = read();     //x氪魅力值,y氪好感度
    for (int i = 1; i <= n; i++)
    {
        a=read(); b=read(); c=read(); d=read();
        girl[i].val = a;        //每个妹子会提升的愉悦值
        if(c > b)
            girl[i].cost = (c - b) * y;     //增加好感度需要的钱
        else
            girl[i].cost = 0;
        if(k < d)
            girl[i].goal = m - (d - k) * x;     //以i为结束,花费在好感度上的钱最多为goal(上限)
        else
            girl[i].goal = m;
    }
    sort(girl + 1, girl + 1 + n, cmp);          //先排序,确保不会影响到别个维度中的选取
    //FOR(i, 1, n) printf("i=%d val=%d cost=%d goal=%d\n", i, girl[i].val, girl[i].cost, girl[i].goal);
    for (int i = 1; i <= n; i++)
    {
        for (int j = girl[i].goal; j >= girl[i].cost; j--)      //从当前目标终点值到最低值,滚动数组优化
            dp[j] = max(dp[j], dp[j - girl[i].cost] + girl[i].val);		
        ans = max(ans, dp[girl[i].goal]);					//每次循环更新ans
    }
    cout<<ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值