洛谷 P4071 [SDOI2016]排列计数(排列组合、逆元、错排问题)
传送门
解题思路
前置知识:错排问题
令 \(f(i)\) 表示 \(i\) 个元素的错排数。则:
\[Ans=C_n^m\times f(n-m)
\]
组合数用维护前缀和+逆元求得,错排提前预处理。
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const long long mod=1e9+7;
const int maxn=1e6+5;
int n,m,T;
long long d[maxn],f[maxn];
long long kuaisumi(long long a,long long b){
if(b==0) return 1;
if(b==1) return a%mod;
long long res=kuaisumi(a,b/2);
if(b&1) return res*res%mod*a%mod;
return res*res%mod;
}
inline long long c(int n,int m){
return d[n]*kuaisumi(d[m],mod-2)%mod*kuaisumi(d[n-m],mod-2)%mod;
}
int main(){
ios::sync_with_stdio(false);
f[0]=1;f[1]=0;f[2]=1;
for(int i=3;i<maxn;i++) f[i]=1ll*(i-1)*(f[i-1]+f[i-2])%mod;
d[0]=1;
for(int i=1;i<maxn;i++) d[i]=d[i-1]*i%mod;
cin>>T;
while(T--){
cin>>n>>m;
cout<<c(n,m)*f[n-m]%mod<<endl;
}
return 0;
}