题解 - 购物

题目描述

小朋友到商场去购物,商场里面的东西太多了,看的小朋友们眼花缭乱。小朋友拿着 m 元钱,准备去购物,商场里有 n 件物品,在小朋友的心目中,每个商品都有一定的价值,比如说书的价值是 10,游戏机的价值是 5,这说明在这个小朋友的心目中学习比玩游戏更重要,是一个爱学习的好孩子 (嘻嘻)。
为了方便购物,小朋友们把所有商品的价格分成了 3 类,第 1 类商品每个价格是 1,第 2 类商品每个的价格是 2,第 3 类商品每个的价格是 3。第 i 个商品的价格是 wi(1 ≤ wi ≤ 3),价值是 vi。
很明显,小朋友希望用不超过 m 元钱买商品,并且要使得买到的商品的价值总和最大。现在,请你来帮助这个小朋友计算这个问题吧。

输入
输入的第一行是 2 个正整数 n 和 m,表示商品的总数和小朋友有的钱。
接下来一行有 n 个正整数 wi,分别表示每个商品的价格。
接下来一行有 n 个正整数 vi,分别表示每个商品在小朋友心目中的价值。

输出
输出可以买到的商品的最大价值总和。
样例输入 Copy
【输入样例1】
3 3
1 2 2
1 2 3

【输入样例2】
5 7
3 2 1 2 1
2 2 1 3 1

【输入样例3】
16 24
1 1 1 1 2 3 1 2 3 3 2 2 3 3 2 3
5 2 5 3 4 10 1 9 6 1 8 5 7 7 6 8
样例输出 Copy
【输出样例1】
4

【输出样例2】
7

【输出样例3】
75
提示
【样例1解释】

这里我们可以选择第 1 件和第 3 件商品,总的价值是 4。

【样例2解释】
选择第 1,3,4 和 5 个商品,也可以选择第 2,3,4 和 5 个物品

【数据范围】
对于所有的数据,保证 1 ≤ n ≤ 105,1 ≤ m ≤ 3×105,1 ≤ wi ≤ 3,1 ≤ vi ≤ 106。

题意

有n个商品,每个商品有价格wi和价值vi,特殊的是1 ≤ wi ≤ 3,问如何用不超过 m 元钱买商品,并且使得买到的商品的总价值最大

分析

本题看似是一道背包问题,但看到数据范围1 ≤ n ≤ 105,1 ≤ m ≤ 3×105,1 ≤ wi ≤ 3,1 ≤ vi ≤ 106,背包肯定会超时,故考虑其他方法

注意到商品一共有3类,价格分别为1,2,3,

故我们可以先把这n件商品划分为3类,

for(int i = 1;i <= n;i++) a[w[i]][++cnt[w[i]]] = v[i];

并且按照价值从大到小排序,因为在价格相同的前提下,肯定优先买价值高的

for(int i = 1;i <= 3;i++) sort(a[i] + 1,a[i] + 1 + cnt[i],greater<int>());

由于我们已经按价值从大到小排序,如果某一类商品买k件的话,肯定是买前k件,故我们可以通过前缀和来优化计算

for(int i = 1;i <= 3;i++)
    for(int j = 1;j <= cnt[i];j++) 
        a[i][j] += a[i][j-1];

之后我们直接枚举每一类买了多少件即可

// i指第三类,j指第二类
for(int i = 0;i <= cnt[3];i++){
    int tmp = m - i * 3; // 用来买第一类和第二类的钱
    // l指买第二类的最小值,即当第一类全部买下时,第二类买的数量最少
    // r指买第二类的最大值,即当第一类全部不买时,第二类买的数量最多
    int l = min(max(0,(tmp - cnt[1]) / 2),cnt[2]),r = min(cnt[2],tmp / 2);
 
    for(int j = l;j <= r;j++){
        int ww = i * 3 + j * 2;
 
        if(ww > m) break; // 如果第三类和第二类的总花费大于m,直接结束循环即可
 
        res = max(res,a[3][i] + a[2][j] + a[1][min(m - ww,cnt[1])]);
    }
}

本题还比较卡时间,故我们开一个火车头优化,即可ac

#pragma GCC optimize(3)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")

代码

#pragma GCC optimize(3)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
 
#include<bits/stdc++.h>
  
using namespace std;
 
typedef long long LL;
 
const int N = 1e5 + 10;
 
int n,m;
int w[N],v[N];
LL res;
 
LL a[4][N];
int cnt[4];
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
     
    cin >> n >> m;
    for(int i = 1;i <= n;i++) cin >> w[i];
    for(int i = 1;i <= n;i++) cin >> v[i];
 
    for(int i = 1;i <= n;i++) a[w[i]][++cnt[w[i]]] = v[i];
 
    for(int i = 1;i <= 3;i++) sort(a[i] + 1,a[i] + 1 + cnt[i],greater<int>());
 
    for(int i = 1;i <= 3;i++)
        for(int j = 1;j <= cnt[i];j++) 
            a[i][j] += a[i][j-1];
     
    for(int i = 0;i <= cnt[3];i++){
        int tmp = m - i * 3;
        int l = min(max(0,(tmp - cnt[1]) / 2),cnt[2]),r = min(cnt[2],tmp / 2);
 
        for(int j = l;j <= r;j++){
            int ww = i * 3 + j * 2;
 
            if(ww > m) break;
 
            res = max(res,a[3][i] + a[2][j] + a[1][min(m - ww,cnt[1])]);
        }
    }
 
    cout << res;
 
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值