POJ 3181 组合数+大数的处理

Dollar Dayz

 POJ - 3181 

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

求1到k中能够组合为n的最组合数

由于k的个数是无限制的,这和完全背包比较相似,因此就需要推一下dp的状态转移方程了,在这里定义一下dp[i][j]表示当前值为i的时候用1到j的组合数的最大值,我们很容易想到

扫描二维码关注公众号,回复: 3398471 查看本文章

1.dp[i][1]=1,还有就是当i<j的时候 dp[i][j]=dp[i][j-1];

2.当i>j的时候就需要思考一下,可以手动模拟前6个,就可以看出当推dp[i][j]的时候,dp[i][j]是由前j个数推出的,即dp[i][j-1],还有一部分,那就是dp[i-j][j],为什么?因为dp[i][j]也是在dp[i-j][j]的基础上加上jz所得出的,因此dp[i][j]=dp[i][j-1]+dp[i-j][j];

但是这样还是不能ac,因为这样di递推的话连long long都会越界,因此只能够用两个long long 类型的数组连接一下,这样就构成前19位,后19位了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll pre[1010][105];
ll back[1010][105];
const int INF=0x3f3f3f3f;
#define rep(i,a,b) for(int i=a;i<=b;i++)
int main(){
    int n,k;
    ll M=1;
    rep(i,1,18) M*=10;
    scanf("%d%d",&n,&k);
    rep(i,0,k)
    back[0][i]=1;
    rep(j,1,k)
    {
        rep(i,1,n)
        {
            if(j>i)
            {
                pre[i][j]=pre[i][j-1];back[i][j]=back[i][j-1];
            }
            else{
                pre[i][j]=pre[i-j][j]+pre[i][j-1]+(back[i-j][j]+back[i][j-1])/M;
                back[i][j]=(back[i-j][j]+back[i][j-1])%M;
            }
        }
    }
    if(pre[n][k]) printf("%I64d",pre[n][k]);
    printf("%I64d\n",back[n][k]);
}

还可以优化

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll pre[1050];
ll back[1050];
const int INF=0x3f3f3f3f;
#define rep(i,a,b) for(int i=a;i<=b;i++)
int main(){
    int n,k;
    ll M=1;
    rep(i,1,18) M*=10;
    scanf("%d%d",&n,&k);
    back[0]=1;
    rep(j,1,k )
    {
           rep(i,1,n)
        {
            if(j>i) continue;
            else{
                pre[i]=pre[i-j]+pre[i]+(back[i-j]+back[i])/M;
                back[i]=(back[i-j]+back[i])%M;
            }
        }
    }
    if(pre[k]) printf("%I64d",pre[n]);
    printf("%I64d\n",back[n]);
}

猜你喜欢

转载自blog.csdn.net/c___c18/article/details/82778413
今日推荐