【杭电oj】1799-循环多少次?(递推公式 && 思路)

题目链接:点击这里

经验:本题mod1007,而n已经到了2000,不能保证互质,所以说什么暴力阶乘啊,乘法逆元啊,费马小定理啊,lucas啊,都不要想了,不如直接递推预处理。

思路:此题需要一点转换的思维,题目中有m个循环,并且我们可以发现后面的循环中的指针一定比前面一个大,并且会出现从n个数中取m个数的所有可能性(前面的数比后面小就行,比如1,3,4),那么问题可以转换为从n个数中取m个数的种类数

也就是说从1->n这n个数中随机选择m个数,只需要将它们按大小顺序填到每一层循环里就可以啦,答案就是C(n,m)。

思路就是这个样子,然后就是计算组合数,可以用递推公式

C(n,m)=C(n-1,m-1) + C(n-1,m)

至于这个公式,高中的时候将排列组合就听老师说过了,不过当时算题都是手算,根本不理解递推公式的重要性,就认为这公式没吉儿用处。。。

公式推导:

等式左边表示从n个元素中选取m个元素,而等式右边表示这一个过程的另一种实现方法:任意选择n中的某个备选元素为特殊元素,从n中选m个元素可以由此特殊元素的分成两类情况,即m个被选择元素包含了特殊元素和m个被选择元素不包含该特殊元素。

然后就是代码了:


#include<bits/stdc++.h>
using namespace std;

int a[2100][2100] = {0};

void inti(void){
    a[0][0] = 1;
    for(int i=1;i<2100;i++){        //C(i,j)
        a[i][0] = 1;
        for(int j=1;j<=i;j++){
            a[i][j] = (a[i-1][j-1] + a[i-1][j])%1007;       
        }
    }
}
int main(void){
    int t,n,m;
    cin>>t;
    inti();
    while(t--){
        cin>>m>>n;
        cout<<a[n][m]<<endl; 
    }
    return 0;
} 

还有就是洋神说的lucas,之前都没听说过,还没看,待补。

猜你喜欢

转载自blog.csdn.net/qq_41009682/article/details/80573871