题目在这里就不贴了
题目大意:有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