Selling Souvenirs CodeForces - 808E (分类排序后DP+贪心)

E. Selling Souvenirs

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

After several latest reforms many tourists are planning to visit Berland, and Berland people understood that it‘s an opportunity to earn money and changed their jobs to attract tourists. Petya, for example, left the IT corporation he had been working for and started to sell souvenirs at the market.

This morning, as usual, Petya will come to the market. Petya has n different souvenirs to sell; ith souvenir is characterised by its weight wiand cost ci. Petya knows that he might not be able to carry all the souvenirs to the market. So Petya wants to choose a subset of souvenirs such that its total weight is not greater than m, and total cost is maximum possible.

Help Petya to determine maximum possible total cost.

Input

The first line contains two integers n and m (1 ≤ n ≤ 100000, 1 ≤ m ≤ 300000) — the number of Petya‘s souvenirs and total weight that he can carry to the market.

Then n lines follow. ith line contains two integers wi and ci (1 ≤ wi ≤ 3, 1 ≤ ci ≤ 109) — the weight and the cost of ith souvenir.

Output

Print one number — maximum possible total cost of souvenirs that Petya can carry to the market.

Examples

input

Copy

1 12 1

output

Copy

0

input

Copy

2 21 32 2

output

Copy

3

input

Copy

4 33 102 72 81 1

output

Copy

10

题意:一个物品个数和容量都是1e5级别的01背包问题,不过物品的花费只有1,2,3思路:先把物品按照花费分为3类,1,2,3,然后排序成降序,先以只取花费为1和2的物品进行DP,然后再用花费为3的物品去尝试更换掉1和2的物品,使总价格最大。还有巨巨有三分的写法,没有看懂= = ,显然太菜了。细节见代码。思路观自大佬的博客:https://blog.csdn.net/yasola/article/details/78222203
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), ‘\0‘, sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
using namespace std;
typedef long long ll;
inline void getInt(int* p);
const int maxn=1000010;
const int inf=0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int n,m;
std::vector<int> v[5];
struct node
{
    int w1;
    int w2;
    ll value;
}dp[maxn];
int main()
{
    gg(n);
    gg(m);
    int x,y;
    repd(i,1,n)
    {
        gg(x),gg(y);
        v[x].pb(y);

    }
    repd(i,1,3)
    {
        sort(all(v[i]),greater<int>());
    }
    repd(i,1,m)
    {
        dp[i]=dp[i-1];
        if(dp[i-1].w1<=sz(v[1])-1&&dp[i].value<dp[i-1].value+v[1][dp[i-1].w1])
        {
            dp[i].value=dp[i-1].value+v[1][dp[i-1].w1];
            dp[i].w1++;
        }
        if(i>1)
        {
            if(dp[i-2].w2<=sz(v[2])-1&&dp[i].value<dp[i-2].value+v[2][dp[i-2].w2])
            {
                dp[i].value=dp[i-2].value+v[2][dp[i-2].w2];
                dp[i].w2=dp[i-2].w2+1;
                dp[i].w1=dp[i-2].w1;
            }
        }

    }
    ll sum=0ll;
    ll ans=0ll;
    for(int i=0;i<=sz(v[3])&&i*3<=m;++i)
    {
        ans=max(ans,sum+dp[m-i*3].value);
        if(i<sz(v[3]))
        {
            sum+=v[3][i];
        }
    }
    printf("%lld\n",ans );
    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ‘ ‘ || ch == ‘\n‘);
    if (ch == ‘-‘) {
        *p = -(getchar() - ‘0‘);
        while ((ch = getchar()) >= ‘0‘ && ch <= ‘9‘) {
            *p = *p * 10 - ch + ‘0‘;
        }
    }
    else {
        *p = ch - ‘0‘;
        while ((ch = getchar()) >= ‘0‘ && ch <= ‘9‘) {
            *p = *p * 10 + ch - ‘0‘;
        }
    }
}


原文地址:https://www.cnblogs.com/qieqiemin/p/10278452.html

时间: 2024-11-02 06:36:40

Selling Souvenirs CodeForces - 808E (分类排序后DP+贪心)的相关文章

Codeforces 459E Pashmak and Graph(dp+贪心)

题目链接:Codeforces 459E Pashmak and Graph 题目大意:给定一张有向图,每条边有它的权值,要求选定一条路线,保证所经过的边权值严格递增,输出最长路径. 解题思路:将边按照权值排序,每次将相同权值的边同时加入,维护每个点作为终止点的最大长度即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 3

Codeforces 830A. Office Keys (背包dp+贪心) / (二分+贪心)

题目链接: http://codeforces.com/problemset/problem/830/A 题意: n个人,k个钥匙(n<=k),p表示这些人要到达的位置 给出n个人的位置以及钥匙的位置,问花时间最多的那个人用时最少是多少?? 思路: 二分+贪心: 二分最少时间,需要对a,b位置数组排序,我们check函数只需要从左到右一个一个找过去,因为如果选后边的点,可能会使结果更差,假如当前这个人选后面的点,那可能会选中后面的人可以选的唯一的钥匙,不会使解更优. check(40)的时候答案

Codeforces 808 E. Selling Souvenirs(三分)

E. Selling Souvenirs 题意: n件物品,有重量和价值,重量只有三种1,2,3.问取不超过m重量的物品的价值总和最大是多少.(n<=1e5,w<=3e5) 思路: n*w很大,常规01背包不能直接做.考虑到物品重量不超过3,可以按重量分类物品.枚举重量3的物品取的件数,可以发现如果重量2的物品取得多则重量1的物品就得取得少,反之亦然.因此所取重量1,2的物品的价值和与重量2物品取的件数应该满足一个上凸函数的关系,即有一个极值点,那个点就是当前枚举下的1,2物品最大价值和.因此

Codeforces Gym101341K:Competitions(DP)

http://codeforces.com/gym/101341/problem/K 题意:给出n个区间,每个区间有一个l, r, w,代表区间左端点右端点和区间的权值,现在可以选取一些区间,要求选择的区间不相交,问最大的权和可以是多少,如果权和相同,则选区间长度最短的.要要求输出区间个数和选了哪些区间. 思路:把区间按照右端点排序后,就可以维护从左往右,到p[i].r这个点的时候,已经选择的最大权和是多少,最小长度是多少,区间个数是多少. 因为可以二分找右端点小于等于当前区间的左端点的某个区间

Codeforces 571B Minimization:dp + 贪心【前后相消】

题目链接:http://codeforces.com/problemset/problem/571/B 题意: 给你一个长度为n的数列a[i]. 现在你可以随意改变数字的位置,问你 ∑| a[i] - a[i+k] | 的最小值(1 <= i <= n-k). 题解: 将a[i]拆成若干个子序列s[j],子序列中相邻两数在a[i]中的距离为k. 此时原式 = ∑(子序列s[j]内部之差的和) 显然,要想使子序列s[j]内部之差的和尽可能小,子序列s[j]内部一定为升序. 显然,要想使 ∑(子序

输入password登录到主界面,录入学生编号,排序后输出

n 题目:输入password登录到主界面,录入学生编号,排序后输出 n 1.  语言和环境 A.实现语言 C语言 B.环境要求 VC++ 6.0 n 2.  要求 请编写一个C语言程序.将若干学生编号按字母顺序(由小到大)输出. 程序的功能要求例如以下: 1)  输入password"admin",正确则进入主界面,错误则直接推出(exit(0)): 2)从键盘输入5个学生编号"BJS1001","BJS2001"."BJS1011&

已知s.txt文件中有一个这样的字符串 请编写程序读取数据内容,把数据排序后写入 ss.txt文件

package cn.idcast5; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; /* * 需求:已知s.txt文件中有一个这样

SQL排序后将序号填入指定字段

1.显示行号 如果数据没有删除的情况下主键与行号是一致的,但在删除某些数据,行号就与主键不一致了,这时需要查询行号就需要用新的方法,在SQL Server2005之前,需要使用临时表,但在SQL Server2005中,使用ROW_NUMBER()非常方便. 以下是一个查询语句,意思是按照cid将数据排序,然后将排序后的序号填入新建的字段rowNum. select row_number() over (order by cid) as rowNum,* from t_gene 查询结果: 2.

Javascript 数组自定义排序,并获取排序后的保存原索引的同位数组(堆排序实现)

比如数组A: [ 0: 5, 1: 2, 2: 4, 3: 3, 4: 1 ] 排序后的结果为:[1, 2, 3, 4, 5],但是有时候会有需求想要保留排序前的位置到一个同位数组里,如前例则为:[4, 1, 3, 2, 0],因此就利用堆排序写了一个单独的数组排序过程加以实现. 代码如下: function arrayKeys(arr) { var i = 0, len = arr.length, keys = []; while (i < len) { keys.push(i++); } r