[SNOI2017] 英雄联盟
题目描述
正在上大学的小皮球热爱英雄联盟这款游戏,而且打的很菜,被网友们戏称为「小学生」。
现在,小皮球终于受不了网友们的嘲讽,决定变强了,他变强的方法就是:买皮肤!
小皮球只会玩 N \text{N} N 个英雄,因此,他也只准备给这 N \text{N} N 个英雄买皮肤,并且决定,以后只玩有皮肤的英雄。
这 N \text{N} N 个英雄中,第 i \text{i} i 个英雄有 K i K_i Ki 款皮肤,价格是每款 C i C_i Ci Q 币(同一个英雄的皮肤价格相同)。
为了让自己看起来高大上一些,小皮球决定给同学们展示一下自己的皮肤,展示的思路是这样的:对于有皮肤的每一个英雄,随便选一个皮肤给同学看。
比如,小皮球共有 5 个英雄,这 5 个英雄分别有 0,0,3,2,4 \text{0,0,3,2,4} 0,0,3,2,4 款皮肤,那么,小皮球就有 3 × 2 × 4 = 24 3 \times 2 \times 4 = 24 3×2×4=24 种展示的策略。
现在,小皮球希望自己的展示策略能够至少达到 M \text{M} M 种,请问,小皮球至少要花多少钱呢?
输入格式
第一行,两个整数 N,M \text{N,M} N,M。
第二行, N \text{N} N 个整数,表示每个英雄的皮肤数量 K i K_i Ki。
第三行, N \text{N} N 个整数,表示每个英雄皮肤的价格 C i C_i Ci。
输出格式
一个整数,表示小皮球达到目标最少的花费。
样例 #1
样例输入 #1
3 24
4 4 4
2 2 2
样例输出 #1
18
提示
样例解释
每一个英雄都只有4款皮肤,每款皮肤2 Q币,那么每个英雄买3款皮肤, 3 × 3 × 3 ≥ 24 3 \times 3 \times 3 \ge 24 3×3×3≥24,共花费 6 × 3 6 \times 3 6×3 Q币。
数据范围
共 10 组数据,第 i \text{i} i 组数据满足: N ≤ max ( 5 , log 2 4 i ) \text{N} \le \max(5, \log_2^4i) N≤max(5,log24i)
100 % \text{100}\% 100% 的数据: M ≤ 1 0 17 , 1 ≤ K i ≤ 10 , 1 ≤ C i ≤ 199 \text{M} \le 10^{17}, 1 \le K_i \le 10, 1 \le C_i \le 199 M≤1017,1≤Ki≤10,1≤Ci≤199。保证有解。
思路
这道题又是那种属于不确定体积的,我们得扩大体积(直接用总Q币钱当作总体积),最后我们只需找到第一个大于给定体积的所对应的下标即可。(也就是找到最小、同时大于M的那一“格”Q币数量)
代码
//可见,这是一道多重背包问题(选的体积有限)
#include<iostream>
#define int long long
using namespace std;
const int N = 1e6+10;
int f[N];//f[i]表示以j的最大花费数
int v[N],w[N];
int n,m;
int sum;//Q币的总量
//这种求至少的背包问题,往往总体积都是最大的。
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>v[i];
for(int i=1;i<=n;i++)cin>>w[i],sum+=w[i]*v[i];
f[0]=1;
for(int i=1;i<=n;i++){
for(int j=sum;j>=0;j--){
for(int k=0;k*w[i]<=j&&k<=v[i];k++){
f[j]=max(f[j],f[j-k*w[i]]*k);
}
}
}
int ans=0;
while(ans<=sum&&f[ans]<m){
ans++;
}
cout<<ans;
return 0;
}