【组合数学】P4071 [SDOI2016]排列计数

传送门:https://www.luogu.com.cn/problem/P4071

分析

就是从 \(n\) 个数中挑 \(n-m\) 个数,然后求 \(n-m\) 的错排个数即可。

\(D_n\) 表示 \(n\) 个数错排的个数,有

错排的通式:\(D_n = n!(1 - \frac{1}{1!} + \frac{1}{2!} - \frac{1}{3!} ... + (-1)^n \frac{1}{n!})\)
错排递推式:\(D_n = (n-1)(D_{n-1} + D_{n-2})\)

代码:

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

typedef long long ll;
#define endl '\n'

const int N=1e6+5, mod=1e9+7;


inline void read(ll &x) {
    int s=0;x=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

ll d[N];

ll fpow(ll x,ll p)
{
    ll res=1;
    for(;p;p>>=1,x=x*x%mod)
        if(p&1)res=res*x%mod;
    return res%mod;
}

ll inv(ll x){
	return fpow(x,mod-2)%mod;
}

ll fac[N];

ll C(ll a, ll b){
	return fac[a]*inv(fac[b])%mod*inv(fac[a-b])%mod;
}

void init(){
	d[1]=0, d[0]=d[2]=1;
	for(int i=3; i<N; i++) d[i]=(i-1)*(d[i-1]+d[i-2])%mod;
	
	fac[0]=1;
	for(int i=1; i<N; i++) fac[i]=fac[i-1]*i%mod;
}


int main(){
	init();
	int T; cin>>T;
	while(T--){
		ll n, m; read(n), read(m);
		cout<<C(n, m)*d[n-m]%mod<<endl;
	}
	return 0;
}
posted @ 2021-05-26 16:22  HinanawiTenshi  阅读(58)  评论(0编辑  收藏  举报