2017福建省大学生程序设计竞赛--K题(错排,组合数学)

来源:互联网 发布:招远淘宝小镇 编辑:程序博客网 时间:2024/06/05 15:14

题目在这里就不贴了


题目大意:有n个人,打乱顺序后,要求至少有k个人能拿到到自己魔杖,问有几种排序方法?


解题思路:

典型的  错排+组合数学

一定要理清错排的思路才能看懂这道题代码,在计算中  组合数学的取模运算还要用到快速幂+费马小定理求逆元。


推荐学习错排的链接:点击打开链接

推荐学习快速幂的链接:点击打开链接


代码如下,细节见代码:

#include<iostream>using namespace std;const int maxn=1e4+5;const int mod=1e9+7;typedef long long ll;ll n,m;int T;ll fac[maxn],dp[maxn],inver[maxn];ll fastmod(ll a,ll b)   //快速幂求 组合数逆元{    ll ans=1;  //初始化基础数为 1    while(b)    {        if(b&1)            ans=ans*a%mod;        a=a*a%mod;        b>>=1;    }    return ans;}void initial()   //初始化{    fac[0]=1;    //初始化基础数为 1    for(ll i=1; i<maxn; i++)    {        fac[i]=(fac[i-1]*i)%mod;    }    inver[maxn-1]=fastmod(fac[maxn-1],mod-2);    //除法计算化作求逆元    for(ll i=maxn-2; i>=0; i--)    {        inver[i]=(inver[i+1]*(i+1))%mod;       //a的p-1次方的逆元是a的p-2次方    }    dp[0]=1;    //初始化基础数为 1    dp[1]=0;    for(ll i=2; i<=maxn; i++)     //递推关系    {        dp[i]=(i-1)*(dp[i-1]+dp[i-2]);        dp[i]%=mod;    }}ll C(ll n,ll m)         //组合数学公式{    return fac[n]*inver[m]%mod*inver[n-m]%mod;}int main(){    initial();    cin>>T;    while(T--)    {        cin>>n>>m;        ll ans=0;        for(ll i=m; i<=n; i++)        {            ans+=C(n,i)*dp[n-i]%mod;     //至少k个人拿到自己的魔杖            ans%=mod;        }        cout<<ans<<endl;    }    return 0;}









~step by step



阅读全文
0 0