AcWing 885. 求组合数 I 模板题 c++详解

本文介绍了如何使用动态规划求解组合数问题,通过c[i][j]=c[i-1][j]+c[i-1][j-1]的递推关系构建二维表格,适用于查询次数较多的情况。对于大规模数据,当a,b数量级超过2e3时,需考虑更高效的解决方案。
摘要由CSDN通过智能技术生成

原题链接:https://www.acwing.com/problem/content/887/

题目分析:

这道就是让我们计算组合数,结果对(1e9+7)取模

组合数计算方法:

组合数公式\binom{i}{j} = \binom{i-1}{j}+\binom{i-1}{j-1}

直观理解:从i张牌中抽出j张,假设王牌(joker)只有一张,则所有方案数可以分为含joker和不含joker两类,这两个集合显然交为空且并为全集,所以含joker与不含joker方案数相加就是总数。含joker则还需要从i-1张中再抽j-1张,不含joker相当于把牌堆中joker撕掉,则从i-1张中抽取j张。

可以看作是一种动态规划方程:c[i][j] = (c[i - 1][j] + c[i - 1][j - 1])

组合数天然的限制i >= j,并且已知 \binom{i}{0}=1,画出二维动态规划表格(拙劣的画工~~)

由c[i][j] = c[i-1][j] + c[i-1][j-1]可知,上两个元素可推出下面一个元素的值

所以我们只需要遍历二维表中右上部分,并且从上向下遍历填表

补充说明:c[1][1]=c[0][1]+c[0][0]=0 +1=1(i<j都是默认为0)

代码

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 2005, mod = 1e9 + 7;
int c[N][N];

void init()
{
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j <= i; j ++ )
            if (!j) c[i][j] = 1;
            else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
 
int main()
{
    int n;
    init();//二维动态规划表构建 
    scanf("%d", &n);
//n次查询 
    while (n -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", c[a][b]);
    }
    return 0;
}

适用范围:先建好表适合查询次数特别多的问题

本题a,b数量级比较小(2e3)所以用O(n^2)能过

若数量级达到1e5甚至1e10,就应当选择其他方法了

假设题目没有给mod,处理方式又有所不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值