好的,我将这道题整理为清晰的题面格式,并补充样例解释、数据范围与时空限制:
题目描述
原题来自:POI 2005
Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有 n 种面值的硬币,面值分别为 b1,b2,…,bn。但是每种硬币有数量限制,现在我们想要凑出面值 k,求最少要用多少个硬币。
输入格式
- 第一行一个整数 n;
- 第二行 n 个整数 b1,b2,…,bn,表示硬币的面值;
- 第三行 n 个整数 c1,c2,…,cn,表示每种硬币的个数;
- 第四行一个整数 k,表示要凑出的面值。
输出格式
输出一行一个整数,表示最少需要付的硬币数。
样例
样例输入
3
2 3 5
2 2 1
10
样例输出
3
样例解释
硬币面值:[2,3,5],数量:[2,2,1],要凑出面值 10。
最少硬币数方案:
- 使用 5 面值硬币 1 枚(剩余 5 需凑)
- 使用 3 面值硬币 1 枚(剩余 2 需凑)
- 使用 2 面值硬币 1 枚(剩余 0)
总共 3 枚硬币。
另一种方案:5+5 但 5 硬币只有 1 枚,不行;2+2+2+2+2 需要 5 枚 2,但只有 2 枚;2+2+3+3 需要 4 枚;所以最少是 3 枚。
数据范围
对于全部数据:
- 1≤n≤200
- 1≤b1<b2<⋯<bn≤2×104
- 1≤ci,k≤2×104
时空限制
- 时间:1000 ms
- 内存:524288 KB
提示
此题为 多重背包 求最小硬币数(每种硬币数量有限),可以用 单调队列优化 或 二进制拆分 转化为 0/1 背包,再求最小值。
方法一:二进制拆分:
- 将每种硬币数量 ci 拆成 1,2,4,…,2t,r(其中 r 是剩余部分);
- 这样每种硬币被拆成 O(logci) 个物品,每个物品价值为 bi,费用为 1(硬币数);
- 问题转化为:有 O(nlogk) 个物品,每个物品体积为 bi,价值为 1,求恰好装满 k 的最小价值(硬币数);
- 用 DP:dp[x] 表示凑出面值 x 的最少硬币数,初始 dp[0]=0,其余为 ∞;
- 对每个物品,dp[j]=min(dp[j],dp[j−bi]+1)(注意是 0/1 背包,需要倒序枚举 j)。
复杂度:O(k⋅nlogk),在 k≤2×104,n≤200 时可行。
方法二:单调队列优化多重背包:
- 对于每种硬币 bi,将 dp 数组按模 bi 的余数分成 bi 组;
- 对于每一组,状态转移为 $dp[j] = \min_{0 \le l \le c_i} \{ dp[j - l\cdot b_i] + l \}$;
- 可以用单调队列维护窗口 [j−ci⋅bi,j] 内 dp[j−l⋅bi]−l 的最小值,从而 O(1) 转移。
复杂度:O(n⋅k),更优。
最终答案:dp[k](若为无穷大则无解,但题目保证有解?实际上可能无解,但根据数据范围应保证有解)。
注意:本题求最小硬币数,初始 dp[0]=0,其余 dp[i]=∞,转移取 min。