Dollar Dayz
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 6074 | Accepted: 2293 |
Description
Farmer John goes to Dollar Days at The Cow Store and discovers an unlimited number of tools on sale. During his first visit, the tools are selling variously for $1, $2, and $3. Farmer John has exactly $5 to spend. He can buy 5 tools at $1 each or 1 tool at $3 and an additional 1 tool at $2. Of course, there are other combinations for a total of 5 different ways FJ can spend all his money on tools. Here they are:
1 @ US$3 + 1 @ US$2
1 @ US$3 + 2 @ US$1
1 @ US$2 + 3 @ US$1
2 @ US$2 + 1 @ US$1
5 @ US$1
Write a program than will compute the number of ways FJ can spend N dollars (1 <= N <= 1000) at The Cow Store for tools on sale with a cost of $1..$K (1 <= K <= 100).
Input
A single line with two space-separated integers: N and K.
Output
A single line with a single integer that is the number of unique ways FJ can spend his money.
Sample Input
5 3
Sample Output
5<span style="font-size:18px;color:#ff0000;">题意:给出两个数,n,m,问m以内的整数有多少种组成n的方法</span><span style="font-size:18px;color:#ff0000;">思路:一看就是完全背包,然后果断敲了,提交,WA,寻找原因所在,发现输入1000,100,时候,输出的明显是垃圾值,那么这题很明显后面的结果会很大, 然而循环1000*100的话,用大数绝对超时,参考别人的代码后,才发现能够用将大数分开处理的方法,下面是原理 </span><pre name="code" class="sio"><p style="line-height:28px; font-family:'ms shell dlg'; font-size:14px"><span style="color:#009900;">整数划分是把一个正整数 N 拆分成一组数相加并且等于 N 的问题.<br style="clear:both" />比如:<br style="clear:both" />6<br style="clear:both" />5 + 1 (序列)<br style="clear:both" />4 + 2, 4 + 1 + 1<br style="clear:both" />3 + 3, 3 + 2 + 1, 3 + 1 + 1 + 1<br style="clear:both" />2 + 2 + 2, 2 + 2 + 1 + 1, 2 + 1 + 1 + 1 + 1<br style="clear:both" />1 + 1 + 1 + 1 + 1 + 1</span></p><p style="line-height:28px; font-family:'ms shell dlg'; font-size:14px"><span style="color:#009900;">假设F(N,M) 整数 N 的划分个数,其中 M 表示将 N 拆分后的序列中最大数</span></p><p style="line-height:28px; font-family:'ms shell dlg'; font-size:14px"><span style="color:#009900;">考虑边界状态:<br style="clear:both" />M = 1 或者 N = 1 只有一个划分 既: F(1,1) = 1<br style="clear:both" />M = N : 等于把M - 1 的划分数加 1 既: F(N,N) = F(N,N-1) + 1 <br style="clear:both" />M > N: 按理说,N 划分后的序列中最大数是不会超过 N 的,所以 F(N,M ) = F(N,N)<br style="clear:both" />M < N: 这个是最常见的, 他应该是序列中最大数为 M-1 的划分和 N-M 的划分之和, 比如F(6,4),上面例子第三行, 他应该等于对整数 3 的划分, 然后加上 2 的划分(6-4) 所以 F(N,M) = F(N, M-1) + F(N-M,M)</span></p> <p><span style="color:#009900;">用动态规划来表示</span></p><p><span style="color:#009900;"> </span></p><p><span style="color:#009900;"><span style="font-family:'ms shell dlg';line-height:28px"> dp[n][m]= dp[n][m-1]+ dp[n-m][m]</span><br style="line-height:28px; font-family:'ms shell dlg'; clear:both; font-size:14px" /><span style="font-family:'ms shell dlg';line-height:28px"> </span><br style="line-height:28px; font-family:'ms shell dlg'; clear:both; font-size:14px" /><span style="font-family:'ms shell dlg';line-height:28px"> dp[n][m]表示整数 n 的划分中,每个数不大于 m 的划分数。</span><br style="line-height:28px; font-family:'ms shell dlg'; clear:both; font-size:14px" /><span style="font-family:'ms shell dlg';line-height:28px"> 则划分数可以分为两种情况:</span><br style="line-height:28px; font-family:'ms shell dlg'; clear:both; font-size:14px" /><span style="font-family:'ms shell dlg';line-height:28px"> </span><br style="line-height:28px; font-family:'ms shell dlg'; clear:both; font-size:14px" /><span style="font-family:'ms shell dlg';line-height:28px"> a. 划分中每个数都小于 m, 相当于每个数不大于 m- 1, 故</span><br style="line-height:28px; font-family:'ms shell dlg'; clear:both; font-size:14px" /><span style="font-family:'ms shell dlg';line-height:28px"> 划分数为 dp[n][m-1].</span><br style="line-height:28px; font-family:'ms shell dlg'; clear:both; font-size:14px" /><span style="font-family:'ms shell dlg';line-height:28px"> </span><br style="line-height:28px; font-family:'ms shell dlg'; clear:both; font-size:14px" /><span style="font-family:'ms shell dlg';line-height:28px"> b. 划分中有一个数为 m. 那就在 n中减去 m , 剩下的就相当</span><br style="line-height:28px; font-family:'ms shell dlg'; clear:both; font-size:14px" /><span style="font-family:'ms shell dlg';line-height:28px"> 于把 n-m 进行划分, 故划分数为 dp[n-m][m];</span> </span></p><pre name="code" class="cpp">#include<iostream> #include<cstdio> #include<cstring> using namespace std; long long b[1005][105]; long long a[1005][105]; long long mod=1e18; int n,k; int main() { 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 j=1;j<=k;j++){ for(int i=1;i<=n;i++){ if(i<j){ a[i][j]=a[i][j-1]; b[i][j]=b[i][j-1]; continue; } b[i][j]=b[i][j-1]+b[i-j][j]+(a[i][j-1]+a[i-j][j])/mod; a[i][j]=(a[i][j-1]+a[i-j][j])%mod; } } if(b[n][k]) printf("%I64d",b[n][k]); printf("%I64d\n",a[n][k]); } return 0; }