2019.9.27 硬币
题目描述
给定N中硬币,其中第i中硬币的面值为Ai,共有Ci个。求用这些硬币能在1-m之间拼出的多少种面值。
输入
第一行是两个数字,表示n和m。
第二行有2*n个数,分别表示a1,a2,…,an,c1,c2,…cn。
输出
一个数字,表示能拼出的面值数。
样例输入
样例输入1 3 10 1 2 4 2 1 1 样例输入2 2 5 1 4 2 1
样例输出
样例输出1 8 样例输出2 4
提示
【数据范围】
100%的数据满足:1<=n<=100,1<=m<=100000
简单的完全背包。但是计算一下,传统的完全背包无法通过时间复杂度,所以我们增加优化,如果状态dp[j]已经可以被满足则不再枚举,直接进行下一个状态。
#include<iostream> #include<cstdio> #include<cstring> #define int long long using namespace std; int n,m,dp[1000050],book[1000050]; struct edge { int a,c; }p[1050]; signed main() { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++)scanf("%lld",&p[i].a); for(int i=1;i<=n;i++)scanf("%lld",&p[i].c); dp[0]=1; book[0]=1; for(int i=1;i<=n;i++) { for(int j=m;j>=1;j--) { if(book[j])continue; for(int k=1;k*p[i].a<=j&&k<=p[i].c;k++) { dp[j]|=dp[j-k*p[i].a]; if(dp[j])book[j]=1; } } } int ans=0; for(int i=1;i<=m;i++) if(dp[i])++ans; printf("%lld",ans); return 0; }
/*====年轻人,瞎搞是出不了省一的,这就是现实====*/