题目描述:
给定n组询问,每组询问给定两个整数a,b,请你输出Ca^b mod(1e9+7)的值。
输入格式:
第一行包含整数n。
接下来n行,每行包含一组a和b。
输出格式:
共n行,每行输出一个询问的解。
数据范围:
1≤n<10000
1<b<a<2000
输入样例:
3
3 1
5 3
2 2
输出样例:
3
10
1
分析步骤:
第一:这道题目很明显就是要我们求一个式子,观察我们的数据范围,a和b最大是2000所以我们如果用for循环的话时间复杂度就是O(n^2),也就是4e6完全可以计算出来,所以我们直接选择for循环将其计算出来。
第二:我们看到这道题是求组合数,例如在8个苹果里面选择2个也就是C8^2。我们可以想一下我们是如何手算这个答案的。我们分子是8*7,分母是2*1将他们的答案相除,得出的答案就是我们的答案。如果我们推广到Cn^k的话我们又如何计算呢?分子是(n!),分母是(k!*(n-k)!),这应该在初中应该已经学过了吧,比如C8^2我们可以计算成分子是(8!),分母是(2!*(8-2)!)我们这个(8-2)!答案刚好可以和8!的阶乘的后面一段抵消。
第三:我们求Cn^k可以相当于求Cn-1^k + Cn-1^(k-1)。因为我们从n个苹果里面选好一个,假设之后的要选的苹果不包含这个苹果的话,就相当于在n-1的苹果的范围内选出k个苹果;如果包含之后要选择的苹果包含了这个苹果,那么就相当于在n-1的范围内选择k-1个苹果。然后我们利用递归就能求出任意的答案了!大家仔细想想!
第四:书写主函数,构建整体框架:
-
首先初始化我们的组合数,将所有的组合数都求出来。
-
输入值,利用while函数不断的输入新的值,由于我们已经初始化,从而得出了我们的答案
-
所以直接输出c[a][b]
第五:初始化我们的组合数答案:
-
我们利用之前分析得出的两层for遍历,第一层范围是从0到N;第二层范围是从0到i因为j绝对不可能大于i的
-
如果j == 0的话,就相当于我们从i个苹果中选择0个所以方案就是只有1种
-
如果j != 0的话,c[i][j] = c[ i - 1 ][ j ] + c[ i - 1 ][ j - 1 ]就可以
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;
}
}
}
}
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010 , mod = 1e9 + 7;
int n ;
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()
{
init();
cin>>n;
while(n--){
int a , b ;
cin>>a>>b;
cout<<c[a][b]<<endl;
}
return 0;
}