题目描述
小朋友到商场去购物,商场里面的东西太多了,看的小朋友们眼花缭乱。小朋友拿着 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;
}