洛谷 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;
}
posted @ 2021-09-18 19:31  尹昱钦  阅读(62)  评论(0编辑  收藏  举报