题意:
给出两个数,n,m,问m以内的整数有多少种组成n的方法
完全背包+大数划分
思路:
dp[i][j] := 用i种价格配出金额j的方案数。
那么dp[i][0] = 1,使用任何价格配出金额0的方案个数都是1(什么都不用)。
递推关系式:
实际上是完全背包问题,只是状态转移方程形式有所不同,不过状态转移的方向是完全相同的。
dp[i][j] = dp[i – 1][j] + dp[i – 1][j – i] + dp[i – 1][j – 2 * i] + … + dp[i – 1][0]
附: 01背包完全背包详解
#include <iostream> #include <cstdio> #include <string.h> #include <string> #include <algorithm> using namespace std; unsigned long long a[105][1005],b[105][1005],inf=1; int main() { int n,m,i; for(int i=0;i<18;i++) inf*=10; while(~scanf("%d%d",&n,&m)) { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(i = 0;i<=m;i++) { a[i][0] = 1;// 使用任何价格配出金额0的方案个数都是1 } for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) { if(j<i) { a[i][j]=a[i-1][j]; b[i][j]=b[i-1][j]; } else { // 处理大数前面的部位,当超过int64时,就开始存入b数组,因为in64是9.22..*10^18次方,保证了两个a想加必定不超过in64 b[i][j]=(b[i-1][j]+b[i][j-i])+(a[i-1][j]+a[i][j-i])/inf; a[i][j]=(a[i-1][j]+a[i][j-i])%inf;//保留后面的部份 } } } if(b[m][n]) printf("%lld",b[m][n]); printf("%lld\n",a[m][n]); } return 0; }