POJ 3181 Dollar Dayz DP
http://poj.org/problem?id=3181
题目大意:
给你n元钱和无限个价钱为1~k的物品,让你求有多少种方法花光这n元钱?
思路:
参考别人的。。
可以看成是整数的划分。
如5 3
1+1+1+1+1
1+1+1+2 1+2+2
1+1+3 2+3
设dp[i][j]为i的划分中最大数不超过j的划分总数。
则dp[i][j]=dp[i][j-1]+dp[i-j][j];
有点像组合的某个公式。
分成两个,最大数不选j的,那么为dp[i][j-1],
最大数选中了j的,即dp[i-j][j]。
值得一提的是结果可能会很大,看到大神的思路是这样的,用两个__int64的整数来模拟高精度。
把一个数拆成两个。
Orz。。
#include<cstdio> #include<cstring> const int MAXN=1000+10; __int64 a[MAXN][MAXN],b[MAXN][MAXN],mod=1; //dp[i][j]为i的划分中最大数为j的数目 int main() { int n,k; for(int i=1;i<=18;i++) mod*=10; while(~scanf("%d%d",&n,&k)) { memset(b,0,sizeof(b)); memset(a,0,sizeof(a)); for(int i=0;i<=k;i++) a[0][i]=1; for(int i=1;i<=n;i++) { for(int j=1;j<=k;j++) { if(i >= j ) { a[i][j]=(a[i][j-1] + a[i-j][j])%mod; //后面的位数 b[i][j]=b[i][j-1]+b[i-j][j] +(a[i][j-1] + a[i-j][j])/mod;//前面的位数 } else { a[i][j]=a[i][j-1]; b[i][j]=b[i][j-1]; } } } if(b[n][k]) printf("%I64d",b[n][k]); printf("%I64d\n",a[n][k]); } return 0; }
新 blog : www.hrwhisper.me