ABC 373 F - Knapsack with Diminishing Values

题目传送门

解题思路

这道题没法二进制优化(因为你试试会发现)

设第 i 个物品选了 k_i 个,价值是 v_i,题目告诉我们这样选所获得的快乐值是:k_iv_i-k_i^2

我们可以先算一下,每多选一个物品,我们可以多收获几的快乐值。

kv-k^2-((k-1)v-(k-1)^2)

=kv-k^2-(kv-v-(k^2+1-2k))

=kv-k^2-(kv-v-k^2-1+2k)

=kv-k^2-kv+v+k^2+1-2k

=v+1-2k

化简成这样你也许就会发现,如果一个物品你选的越少,那么你收获的快乐值会越大。

于是,我们可以使用贪心思想,先把所有物品选一个的快乐值放到一个大根堆里,然后再将选两个的放进堆里,以此类推……(直到背包装不下)

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
priority_queue<int> q[5001];
int f[5001],ans;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin>>n>>m;
    int u,v;
    for(int i=1;i<=n;i++)
    {
        cin>>u>>v;
        q[u].push(v-1);
    }

    for(int i=1;i<=m;i++)
    {
        if(q[i].empty())continue;
        for(int j=1;j<=m/i;j++)
        {
            if(q[i].empty())break;
            int u=q[i].top();
            q[i].pop();
            for(int k=m;k>=i;k--)
            {
                f[k]=max(f[k],f[k-i]+u);
            }
            q[i].push(u-2);
        }
    }
    for(int i=1;i<=m;i++)
    {
        ans=max(ans,f[i]);
    }
    cout<<ans;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值