AcWing 1021. 货币系统
\(AcWing\) \(1021\). 货币系统
一、题目描述
给你一个\(n\)种面值的货币系统,求组成面值为\(m\)的货币有多少种方案。
输入格式
第一行,包含两个整数\(n\)和\(m\)。
接下来\(n\)行,每行包含一个整数,表示一种货币的面值。
输出格式
共一行,包含一个整数,表示方案数。
数据范围
\(n≤15,m≤3000\)
输入样例:
3 10
1
2
5
输出样例:
10
二、题目解析
本题与上一题买书问题基本一模一样,只是方案数可能很大,需要用long long
来存储。
状态表示
\(f[i][j]\)表示用前i种面值的货币组成面值为\(j\)的方案数
状态转移方程为\(f[i][j] = f[i-1][j] + f[i][j-v]\)
边界状态为\(f[0][0] = 1\)
三、实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 20;
const int M = 3010;
int n, m;
LL v[N];
LL f[M];
int main() {
cin >> n >> m;
f[0] = 1;
for (int i = 1; i <= n; i++) {
cin >> v[i];
for (int j = v[i]; j <= m; j++)
f[j] += f[j - v[i]];
}
printf("%lld\n", f[m]);
return 0;
}
四、 扩展阅读:重复组合公式
重复组合
重复组合(\(Combination\) \(With\) \(Repetition\))(重复组合)是组合数学中的一种计数方法,用于计算从一个包含\(n\)个对象的集合中选择\(k\)个对象的方式数,这其中 允许出现重复的对象 但是顺序不重要。
计算公式
从\(n\)个不同的元素每次取出\(r\)个元素的 允许重复 组合总数为:
公式证明(插板法)
把\(n\)种元素当成\(n\)个顺序摆放的盒子,\(r\)个完全相同的球,这样从\(n\)种元素中有重复取\(r\)个元素的方法就转化成,把\(r\)个同质球放入\(n\)个盒子的方法。
为什么可以这样呢?想一想,把一个球放到第\(i\)个盒子就相当于从\(n\)种元素中我们取的第\(i\)种元素,如果有多个球放在第\(i\)个盒子中,相当于从\(n\)个元素中重复了取了第\(i\)种元素。
空间中\(n+1\)条 ‘|’ 把空间分成\(n\)个盒子
举个例子\(n=6\),也就是\(6\)个盒子
盒子1 | 盒子2 | 盒子3 | 盒子4 | 盒子5 | 盒子6 |
---|
那么我们往里面放球用 \(\bullet\) 表示
则有
\(\bullet\) | \(\bullet\) \(\bullet\) \(\bullet\) \(\bullet\) | \(\bullet\) \(\bullet\) \(\bullet\) | \(\bullet\) |
---|
我们发现,除去两边边界的 |
实际的摆放方法就是\(n-1\)个 | 和 \(r\)个 \(\bullet\) 的不同摆放方式
所以共有\(n+r-1\)个位置
我们从中选择\(r\)个位置放上小球即可
因此得到公式
利用公式估算数据范围
最坏的情况
最坏的情况为存在\(15\)种货币且每种货币的价值为\(1\),要求组合成价值\(3000\)的货币,每种货币无个数限制。
由于题目中说了,每种货币的价值并不相同,也就是上面论述的每个盒子里面不能随意放入最多\(r\)个小球,受每个盒子上限不同的限制。根据公式求出的数值,肯定是大于真实的数值。
按公式计算出的数值,要大于int
的范围,如果此题数据为最坏情况,那么long long
也会爆掉。