NFLSOJ 6834 中国梦
题面
题目描述
崔真言 在梦里梦见自己代表祖国赴 America参加了国际信息学奥林匹克竞赛(International Olympiad in Informatics,简称 IOI
czy AK IOI)并获得了金牌czy orz,颁奖会结束后崔真言想到附近的超市去买些礼物带回国送给班里的小伙伴们,崔真言心想America的巧克力是食物中的王者,给小伙伴们每人买一盒巧克力肯定会大受欢迎。于是崔真言一进超市就直奔装有巧克力的货架,一口气拿了 40 盒 巨佬牌 巧克力,然后到收银台去排队结帐, 轮到崔真言结账时,他发现自己身上只有一张大面额的Dollar了,于是他把这张钞票递了 过去,收银员迅速在收银机上算出了要找给崔真言的金额,然后打开钱柜准备找钱,崔真言看 到钱柜里的硬币按面额从大到小整整齐齐地摆放着,一种面额的硬币垒成一列,见此情景崔真言一给在座的各位出了一道题
输入格式
输入数据第一行有两个用空格隔开的整数 NN 和 KK,其中 1≤N≤3001≤N≤300,表示超市收银员 要找给小 ZZ 的金额,1≤K≤81≤K≤8,表示收银员的钱柜里共有 KK 种不同面额的硬币。
第 2 2 2 到 K + 1 K+1 K+1行每行包含一个正整数 C i C_i Ci ,其中 1 ≤ C i ≤ 100 1≤C_i≤100 1≤Ci≤100,表示一种硬币的面额,在输入数据中硬币 面额按降序排列(从最大到最小)。不同种类的硬币面额各不相同,每种硬币都取之不尽 用之不竭。
输出格式:
输出数据仅有一行包含一个整数,表示超市收银员可能的找零方案数。答案保证不会 超出长整型范围。需要注意的是如果没有面额为 1 1 1 分的硬币,有些金额将无法找零,此时 结果就输出 0 0 0
数据范围与提示
10 % 10\% 10% 的数据满足: N ≤ 50 N≤50 N≤50, K ≤ 3 K≤3 K≤3, C i ≤ 10 C_i≤10 Ci≤10
30 % 30\% 30% 的数据满足: N ≤ 100 N≤100 N≤100, K ≤ 5 K≤5 K≤5, C i ≤ 20 C_i≤20 Ci≤20
60 % 60\% 60%的数据满足: N ≤ 100 N≤100 N≤100, K ≤ 7 K≤7 K≤7, C i ≤ 50 C_i≤50 Ci≤50
100 % 100\% 100% 的数据满足: N ≤ 300 N≤300 N≤300, K ≤ 8 K≤8 K≤8, C i ≤ 100 C_i ≤100 Ci≤100
样例数据:
样例输入:
83 5
50
25
10
5
1
样例输出:
159
样例说明:
输入详解:收银员要找给小 Z 金额 83 83 83 分,共有 5 5 5 种硬币,面额分别为: 50 , 25 , 10 , 5 , 1 50,25,10, 5, 1 50,25,10,5,1
输出详解:以下是全部 159 159 159 种找零方案中的 前 15 15 15 种和最后一种:
0 × 500 × 250 × 100 × 583 × 1 0×50 0×25 0×10 0×5 83×1 0×500×250×100×583×1
0 × 500 × 250 × 101 × 578 × 1 0×50 0×25 0×10 1×5 78×1 0×500×250×101×578×1
0 × 500 × 250 × 102 × 573 × 1 0×50 0×25 0×10 2×5 73×1 0×500×250×102×573×1
0 × 500 × 250 × 103 × 568 × 1 0×50 0×25 0×10 3×568×1 0×500×250×103×568×1
0 × 500 × 250 × 104 × 563 × 1 0×50 0×25 0×10 4×5 63×1 0×500×250×104×563×1
0 × 500 × 250 × 105 × 558 × 1 0×50 0×25 0×10 5×5 58×1 0×500×250×105×558×1
0 × 500 × 250 × 106 × 553 × 1 0×50 0×25 0×10 6×5 53×1 0×500×250×106×553×1
0 × 500 × 250 × 107 × 548 × 1 0×50 0×25 0×10 7×5 48×1 0×500×250×107×548×1
0 × 500 × 250 × 108 × 543 × 1 0×50 0×25 0×10 8×5 43×1 0×500×250×108×543×1
0 × 500 × 250 × 109 × 538 × 1 0×50 0×25 0×10 9×5 38×1 0×500×250×109×538×1
0 × 500 × 250 × 1010 × 533 × 1 0×50 0×25 0×10 10×5 33×1 0×500×250×1010×533×1
0 × 500 × 250 × 1011 × 528 × 1 0×50 0×25 0×10 11×5 28×1 0×500×250×1011×528×1
0 × 500 × 250 × 1012 × 523 × 1 0×50 0×25 0×10 12×5 23×1 0×500×250×1012×523×1
0 × 500 × 250 × 1013 × 518 × 1 0×50 0×25 0×10 13×5 18×1 0×500×250×1013×518×1
0 × 500 × 250 × 1014 × 513 × 1 0×50 0×25 0×10 14×5 13×1 0×500×250×1014×513×1
……………………………………………
1 × 501 × 250 × 101 × 53 × 1 1×50 1×25 0×10 1×5 3×1 1×501×250×101×53×1
思路:
又是一道背包水题。
灰常简单啊!
要注意的是这个可以找零钱是有无限张的,所以这是个完全背包!
我们设
f
i
f_{ \ i \ }
f i 表示价值为
i
{ \ i \ }
i 时,最多有多少种解。
则可以轻松得到状态转移方程
{ \ }
f
i
+
=
f
i
−
w
[
i
]
f_{ \ i \ } += f_{ \ i - w[ \ i \ ] \ }
f i +=f i−w[ i ]
然后就没有然后了
贴上代码:
#include<bits/stdc++.h>
#define int long long
#define mem(a) memset(a,0,sizeof(a))
#define set(a,b) memset(a,b,sizeof(a))
const int MAXN = 0x3f3f3f3f;
using namespace std;
int in(){ //快读 in()
int x=0,f=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-') f=-1;
c=getchar();
}
while(isdigit(c)){
x=x*10+c-'0';
c=getchar();
}
return x*f;
} //可以不看哦!!
int m, n;
int w[1000005];
int f[1000005]; //背包
signed main(){
cin >> m >> n;
for(int i = 1; i <= n; i++)
cin >> w[i];
f[0] = 1;
for(int i = 1; i <= n; i++)
for(int j = w[i]; j <= m; j++)
f[j] += f[j - w[i]];
cout << f[m] << endl;
return 0;
}