Knapsack( The 2023 ICPC Asia Nanjing Regional Contest (The 2nd Universal Cup. Stage 11: Nanjing)

Little Cyan Fish, an inexperienced businessman, recently launched a store named Queen’s Organic Jewelry. This jewelry store houses n n n gemstones, where the i i i-th gemstone is priced at w i w_i wi dollar and has a beauty of v i v_i vi. Prior to visiting the store, you have W W W dollars in hand, which you plan to use to purchase gemstones of the greatest possible total beauty.

Interestingly, Little Cyan Fish’s store is running a promotion today. Any visitor to the store can select any k k k gemstones and take them home absolutely free of charge! With this opportunity at hand, you’re keen to know the maximum total beauty of gemstones you could obtain with your W W W dollars, assuming you adopt the optimal strategy.

Please bear in mind that the store stocks only one unit of each gemstone, so you cannot obtain the same gemstone more than once. Also note that you don’t have to spend all the money.

Input

There is only one test case in each test file.

The first line of the input contains three integers n n n, W W W and k k k ( 1 ≤ n ≤ 5 × 1 0 3 1 \leq n \leq 5 \times 10^3 1n5×103, 1 ≤ W ≤ 1 0 4 1 \leq W \leq 10^4 1W104, 0 ≤ k ≤ n 0 \leq k \leq n 0kn), indicating the total number of gemstones in the store, the amount of money you have and the number of gemstones you can take for free.

For the following n n n lines, the i i i-th line contains two integers w i w_i wi and v i v_i vi ( 1 ≤ w i ≤ W 1 \leq w_i \leq W 1wiW, 1 ≤ v i ≤ 1 0 9 1 \leq v_i \leq 10^9 1vi109), indicating the price and the beauty of the i i i-th gemstone.

Output

Output one line containing one integer indicating the answer.

Examples

Input

4 10 1
9 10
10 1
3 5
5 20

Output

35

Input

5 13 2
5 16
5 28
7 44
8 15
8 41

Output

129

题目大意

Little Cyan Fish开了一家名为“Queen’s Organic Jewelry”的珠宝店。店里有 n n n颗宝石,每颗宝石有一个价格 w i w_i wi 和美度 v i v_i vi。你手上有 W W W元钱,打算用这 W W W元购买尽可能高总美度的宝石。店里还在做促销活动,你可以免费选择 k k k颗宝石带回家,免费的宝石不需要花费钱。

你需要计算在有限的 W W W元钱下,结合免费选择的 k k k颗宝石,你能获得的最大总美度。

解题思路

  1. 0/1背包问题:这个问题本质上是一个背包问题。你可以将每个宝石看作一个物品,物品的重量就是价格 w i w_i wi,物品的价值就是美度 v i v_i vi。我们要解决的就是在有 W W W元预算的情况下,选择一定数量的宝石,使得其总美度最大。

  2. 免费宝石选择:这里的难点在于可以选择 k k k颗免费宝石。免费的宝石并不需要花费金钱,因此这部分宝石不受预算限制,但是它们也有一个美度限制。因此,我们需要处理两部分:

    • 购买宝石:这部分宝石需要受到预算限制,属于经典的0/1背包问题。
    • 免费宝石:从剩余的宝石中选出 k k k个美度最高的宝石来获得。
  3. 策略设计

    • 首先,将所有宝石按价格 w i w_i wi从小到大排序。
    • 使用动态规划(0/1背包)来处理购买宝石的部分。通过动态规划,记录在不同预算下能达到的最大美度。
    • 然后,对于剩下的宝石,使用一个优先队列(堆)来维护 k k k个最大美度的宝石,并计算出这部分宝石的最大美度和。
  4. 具体步骤

    • 先进行背包动态规划,计算在不同预算下能获得的最大美度。
    • 然后,从排序后的宝石列表中选择 k k k个美度最高的宝石,逐步计算当选择了不同数量的免费宝石时,总美度的最大值。
    • 最终得到的最大美度就是在给定预算和免费宝石选择下的最优解。

代码分析

#include <map>
#include <set>
#include <fstream>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <bitset>
#include <iomanip>
#define endl '\n'
#define int long long
#define Max(a, b) (((a) > (b)) ? (a) : (b))
#define Min(a, b) (((a) < (b)) ? (a) : (b))
#define BoBoowen ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
using namespace std;

const int inf = 1e9 + 7;
const int N = 2e5 + 10;

struct Node
{
    int w;
    int v;
} node[N];

int dp[N]; // 动态规划数组
int ans[N]; // 存储从后向前计算的最多可获得的美度

bool cmp(Node x, Node y)
{
    return x.w < y.w; // 按照宝石的价格升序排序
}

void solved()
{
    int n, w, k;
    cin >> n >> w >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> node[i].w >> node[i].v; // 输入每个宝石的价格和美度
    }
    sort(node + 1, node + 1 + n, cmp); // 按价格排序

    ans[n + 1] = 0;
    priority_queue<int> q; // 优先队列,用于维护免费宝石的最大美度
    int sum = 0;
    for (int i = n; i >= 1; i--)
    {
        if (q.size() < k)
        {
            q.push(-node[i].v); // 将美度最大的宝石放入队列
            sum += node[i].v;
        }
        else
        {
            if (!q.empty() && -q.top() < node[i].v) // 如果队列满了,替换美度最小的宝石
            {
                sum += node[i].v;
                sum += q.top();
                q.pop();
                q.push(-node[i].v);
            }
        }
        ans[i] = sum; // 记录当前从i到n的最大美度
    }

    int maxx = 0;
    for (int i = 0; i <= n; i++) // 从0到n枚举购买宝石的情况
    {
        for (int j = w; j >= node[i].w; j--) // 动态规划更新
        {
            dp[j] = max(dp[j], dp[j - node[i].w] + node[i].v);
        }
        maxx = max(maxx, dp[w] + ans[i + 1]); // 取最大值
    }

    cout << maxx << endl; // 输出最大美度
}

signed main()
{
    BoBoowen;
    int T = 1;
    while (T--)
    {
        solved(); // 解决问题
    }
    return 0;
}

详细分析

  1. 结构体Node:用于存储每个宝石的价格和美度信息。

    struct Node
    {
        int w; // 价格
        int v; // 美度
    } node[N];
    
  2. 动态规划数组 dp:用于记录在预算j下,可以获得的最大美度。

    int dp[N];
    
  3. ans数组:记录从每个位置向后免费选择宝石的最大美度。

    int ans[N];
    
  4. 排序:按价格对宝石进行升序排序。

    sort(node + 1, node + 1 + n, cmp);
    
  5. 优先队列 q:用于维护当前可以选择的最多 k k k个最大美度的免费宝石。

  • 通过优先队列,确保每次选出美度最大的宝石,并替换掉美度较小的宝石。
  1. 动态规划:通过状态转移方程来计算在不同预算下,能够购买的最大美度。

  2. 最终答案:通过比较购买宝石和免费宝石的最大美度来得到最终答案。

时间复杂度

  1. 排序O(n log n)
  2. 动态规划O(n * W),其中 W W W是背包的容量(最大预算)。
  3. 优先队列O(n log k),每个宝石处理时可能进行一次堆操作。

因此,总的时间复杂度是O(n * W + n log n + n log k),在最坏情况下,n = 5000W = 10000k = n时,整体时间复杂度是可以接受的。

总结

这道题综合了0/1背包和最大选择问题的思想。首先通过动态规划计算在给定预算下能获得的最大美度,然后利用优先队列来选择 k k k个免费宝石,最后合并两者的最大美度,得出最终的最优解。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐