划分数

题述
有n个无区别的物品,将它们划分成不超过m组,求出划分方法数模M的余数。
限制条件
1<=m<=n<=1000
2<=M<=10000
样例
输入
4 3
10000
输出
4
题记
dp[i][j]:j的i划分的总数
dp[i][j]=dp[i][j-i]+dp[i-1][j]

本题是来自<挑战程序设计竞赛>虽然书中说了该题的递推式的原因,但是不够清楚,我经过思考认为是这样的:我们在计算过程中只是计算总数,并不清楚到底该几个分成一组这样的细节。如果考虑n的m划分,每一组的物品数量为ai(1<=i<=m),如果说每个ai都满足ai>=1,那么每个ai-1之后就对应了n-m的m划分,这一点很好理解。另外一种情况,如果存在ai=0,意思就是说我们虽然分了m组,但是有些组的物品数是0,那么可以表示成dp[i-1][j]。这一点是难点。假设当前这样分有k个组都是0个物品(k>=0),那么我们可以利用前面算的dp[i-1][j],划分当中存在某些组为0肯定不行啊,我们只看第k个,它占用了一个划分,这是没有意义的,当然就可以写成dp[i-1][j],但是我们怎么知道到底有几个ai为0呢,难道还要对k循环吗?其实不用,因为dp[i-1][j]已经帮我们算了k>=1的情况,我们只用考虑第k个为0的情况。
附加注释
另外一点需要注意的就是dp[0][0]=1,这点很重要,这是之后计算的根本!!!
代码如下

#include <iostream>
//划分数
using namespace std;

const int Maxn=1005;

//输入
int m,n;
int M;

//j的i划分的总数
int dp[Maxn][Maxn];

void solve(){
     //0个划分为0组有1种不同的划分方法
     dp[0][0]=1;
     for(int i=1;i<=m;i++){
         for(int j=0;j<=n;j++){
             if(j-i>=0)                                    //物品个数比划分组数多
                 dp[i][j]=(dp[i-1][j]+dp[i][j-i])%M;
             else                                          //划分组数比物品个数还要多(存在一些组存在1个物品都没有)
                 dp[i][j]=dp[i-1][j];
         }
     }
     printf("%d\n",dp[m][n]);
}

int main()
{
    scanf("%d %d",&n,&m);
    scanf("%d",&M);

    solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值