题意:很容易看懂,一家商店有K种物品,价值分别是1到K,都有无数件,你有N元钱,问你花光N元钱的方法有多少种.
很容易想到 dp[i][j] 表示前i种物品可买J元的方法数。
则有以下地推公式。
if(j >= i)
dp[i][j]=dp[i−1][j]+dp[i][j−i];
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
]
[
j
−
i
]
;
else
dp[i][j]=dp[i−1][j];
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
;
但是本题数据范围会爆int,所以要使用高精度,设置另外一个数组,存储 > INF的部分,把他们分成两个部分。
代码如下:
#include<iostream>
#include<string>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAX_N = 1010;
const int MAX_K = 110;
ll dp[MAX_K][MAX_N],dp2[MAX_K][MAX_N];
const ll INF = 1e16;
int N,K;
void solve(){
memset(dp,0,sizeof(dp));
memset(dp2,0,sizeof(dp2));
dp[0][0] = 1;//这里是因为当i == j时也要执行+1,所以把0置位0.
for(int i=1;i<=K;++i){
for(int j=0;j<=N;++j){//dp[i][0]也要被更新,当然也可以放到前面更新。
if(j >= i){
dp[i][j] = dp[i-1][j] + dp[i][j-i];
dp2[i][j] = dp2[i-1][j] + dp2[i][j-i];
}
else{
dp[i][j] = dp[i-1][j];
dp2[i][j] = dp2[i-1][j];
}
if(dp[i][j] >= INF){
dp2[i][j] += (dp[i][j]/INF);
dp[i][j] %= INF;
}
}
}
if(dp2[K][N])
cout << dp2[K][N];
cout << dp[K][N] << endl;
}
int main(void){
cin >> N >> K;
solve();
return 0;
}
当然这一题也可以使用一维滚动数组,代码如下:
#include<iostream>
#include<cstring>
#include<cmath>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
const int MAX_N = 110;
const int MAX = 1010;
typedef long long ll;
ll dp[MAX],dp2[MAX];
const ll INF = 1e16;
int K,N;
void solve(){
dp[0] = 1;
for(int i=1;i<=K;++i){
for(int j=i;j<=N;++j){
dp[j] = dp[j] + dp[j-i];
dp2[j] = dp2[j] + dp2[j-i];
if(dp[j] >= INF){
dp2[j] += (dp[j]/INF);
dp[j] %= INF;
}
}
}
if(dp2[N])
cout << dp2[N];
cout << dp[N] << endl;
}
int main(void){
cin >> N >> K;
solve();
return 0;
}