原题链接:https://www.acwing.com/problem/content/887/
题目分析:
这道就是让我们计算组合数,结果对(1e9+7)取模
组合数计算方法:
组合数公式:
直观理解:从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,并且已知 ,画出二维动态规划表格(拙劣的画工~~)
由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,处理方式又有所不同。