题意:数额为N的金钱,问用面值为1,2,3...k的钱可以有多少种不同的组合方法。
分析:完全背包。要用到高精度。
把一个大数分成高位和低位两部分。模拟加法运算。
Code:
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define LL long long using namespace std; const int maxn=1010; const LL inf=1000000000000000000; LL high[maxn],low[maxn]; int main() { int n,k; while(scanf("%d %d",&n,&k)==2){ memset(high,0,sizeof(high)); memset(low,0,sizeof(low)); low[0]=1; for(int i=1;i<=k;i++){ for(int j=i;j<=n;j++){ high[j]=high[j]+high[j-i]+(low[j]+low[j-i])/inf; low[j]=(low[j]+low[j-i])%inf; } } if(high[n]==0) printf("%I64d\n",low[n]); else printf("%I64d%I64d\n",high[n],low[n]); } return 0; }
另一种高精度处理方法。其实和上面是一个道理,只是每个数组只存储一位数。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int dp[1010][55]; int n,k; void ADD(int x,int y){ for(int i=0;i<=50;i++){ dp[x][i]+=dp[y][i]; if(dp[x][i]>=10){ dp[x][i]-=10; dp[x][i+1]+=1; } } } int main() { while(scanf("%d %d",&n,&k)==2){ memset(dp,0,sizeof(dp)); dp[0][0]=1; for(int i=1;i<=k;i++){ for(int j=i;j<=n;j++){ ADD(j,j-i); } } int idx=51; while(idx>0&&dp[n][idx]==0) idx--; while(idx>=0) printf("%d",dp[n][idx--]); printf("\n"); } return 0; }