uva—How do you add?

来源:互联网 发布:waphyseccom软件下载 编辑:程序博客网 时间:2024/06/05 18:57


Problem A: How do you add?

Larry is very bad at math - he usually uses a calculator, which worked well throughout college. Unforunately, he is now struck in a deserted island with his good buddy Ryan after a snowboarding accident. They're now trying to spend some time figuring out some good problems, and Ryan will eat Larry if he cannot answer, so his fate is up to you!

It's a very simple problem - given a number N, how many ways canK numbers less than N add up to N?

For example, for N = 20 and K = 2, there are 21 ways:
0+20
1+19
2+18
3+17
4+16
5+15
...
18+2
19+1
20+0


Input

Each line will contain a pair of numbers N and K.N and K will both be an integer from 1 to 100, inclusive. The input will terminate on 2 0's.

Output

Since Larry is only interested in the last few digits of the answer, for each pair of numbersN and K, print a single number mod 1,000,000 on a single line.

Sample Input

20 220 20 0

Sample Output

2121
题意:给出两个数N,K,N代表数的大小,K代表将N拆成几个数相加,问N对K能有多少种组合?

分析:

法一:典型的递推DP是有规律的,一开始可能想不通,可以先写出一些简单的情况加以总结。

          1 1:1->1

          1 2:0+1,1+0->2

          1 3:0+0+1,0+1+0,1+0+0->3

          2 1:2->1

          2 2:0+2,1+1,2+0->3

          2 3:0+0+2,0+2+0,2+0+0,0+1+1,1+0+1,1+1+0->6

          3 1:3->1

          3 2:0+3,1+2,2+1,3+0->4

          3 3:0+0+3,0+3+0,3+0+0,0+1+2,0+2+1,1+2+0,2+1+0,1+0+2,2+0+1,1+1+1->10

     由上发现好像(2 2)=(1 2)+(2 1),(2 3)=(1 3)+(2 2),(3 2)=(2 2)+(3 1),(3 3)=(2 3)+(3 2)

     即:dp[N][K]=dp[N-1][K]+dp[N][K-1],我们想一下,为什么是这样呢?

     用递推的思想,当你求(3 3)的时候,实际上就是(3 2)再加一位0,(2 3)在某一位上加1,依次递推下去......

     因此有,dp[N][K]=dp[N-1][K]+dp[N][K-1]


void init(){    memset(dp,0,sizeof(dp));    dp[0][0]=1;//初始化!!!    for(int i=1;i<101;i++)//还有i是从1开始的    {        dp[0][i]=1;///(3 1)->1        for(int j=1;j<101;j++)///需要注意的是dp[j][i]的循环而不是dp[i][j],你在求(3 3)的时候保证///(2 3)和(3 2)都已经求出来了,因此应该是同一位数的先都求出来。            dp[j][i]=(dp[j][i-1]+dp[j-1][i])%MOD;    }}
法二:由上,我们不难想到另一种方法dp[i][j] = sum{ dp[i-1][j-t] } 表示当前这一位填p

           dp[i][j] 表示i个不超过N的非负整数加起来的和为j的方法数(刚好与上面相反dp[K][N])

void init(){    memset(dp,0,sizeof(dp));    for(int i=0;i<101;i++)        dp[i][0]=1;    for(int i=1;i<101;i++)        for(int j=1;j<101;j++)            for(int t=0;t<=j;t++)                dp[i][j]=(dp[i][j]+dp[i-1][j-t])%MOD;}

法三:组合数学的思想——隔板法

          关于组合排列的问题,高中经常做到。

          把一个数分成几个数相加,相当于把该数大小看成球的个数N,然后将球放入K个盒子(可空)中,有几种放法。

就是要放入k-1个板  ,即C(N+K-1, K-1)

代码:

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define N 102#define MOD 1000000int dp[N][N];/*void init(){    memset(dp,0,sizeof(dp));    for(int i=0;i<101;i++)        dp[i][0]=1;    for(int i=1;i<101;i++)        for(int j=1;j<101;j++)            for(int t=0;t<=j;t++)                dp[i][j]=(dp[i][j]+dp[i-1][j-t])%MOD;}*/void init(){    memset(dp,0,sizeof(dp));    dp[0][0]=1;    for(int i=1;i<101;i++)    {        dp[0][i]=1;        for(int j=1;j<101;j++)            dp[j][i]=(dp[j][i-1]+dp[j-1][i])%MOD;    }}int main(){    int n,k;    init();    while(scanf("%d%d",&n,&k),n&&k)        cout<<dp[n][k]<<endl;    return 0;}


0 0
原创粉丝点击