题目描述
本题中,你需要解决完全背包问题。
有 \(n\) 种物品,第 \(i\) 种物品单个体积为 \(v_i\)、价值为 \(c_i\)。
\(q\) 次询问,每次给出背包的容积 \(V\),你需要选择若干个物品,每种物品可以选择任意多个(也可以不选),在选出物品的体积的和恰好为 \(V\) 的前提下最大化选出物品的价值的和。你需要给出这个最大的价值和,或报告不存在体积和恰好为 \(V\) 的方案。
为了体现你解决 NP-Hard 问题的能力,\(V\) 会远大于 \(v_i\),详见数据范围部分。
输入格式
第一行两个整数 \(n,q\),表示物品种数和询问次数。
接下来 \(n\) 行每行两个整数 \(v_i,c_i\) 描述一种物品。
接下来 \(q\) 行每行一个整数 \(V\) 描述一次询问中背包的体积。
输出格式
对于每组询问输出一行一个整数。若不存在体积和恰好为 \(V\) 的方案,输出 -1
;否则输出最大的选出物品的价值和。
样例 #1
样例输入 #1
2 2
6 10
8 15
100000000001
100000000002
样例输出 #1
-1
187500000000
提示
样例解释 1
第二组询问的最优方案为:选择 \(3\) 个物品 \(1\) 和 \(12499999998\) 个物品 \(2\)。
子任务
对于所有测试数据,\(1 \le n \le 50, 1 \le v_i \le 10^5, 1 \le c_i \le 10^6, 1 \le q \le 10^5, 10^{11} \le V \le 10^{12}\)。
题目来源
来自 2023 清华大学学生程序设计竞赛暨高校邀请赛(THUPC2023)初赛。
思考当 \(V\) 非常大的时候,选的数有没有什么规律?
容易想到,一定有一个物品被选了很多次。结合 \(n\le50\),猜测需要去枚举哪种物品选择了很多次。
然后大概减到一定次数之内,就不一定是拼命选这个数了。预处理出 \(v_i\le 5\times 10^6\) 以内完全背包的答案。每次选物品选到容量小于等于 \(5\times 10^6\),然后就用完全背包的方法去选就行了。
#include
using namespace std;
const int N=5e6+5,M=5e6;
int n,q;
long long s,dp[N],v[N],c[N],w,ans,k;
int main()
{
memset(dp,-0x7f,sizeof(dp));
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d%d",v+i,c+i);
dp[0]=0;
for(int i=1;i<=n;i++)
{
for(int j=v[i];j