​传送门​

排列计数[luogu4071][逆元][错排列]_预处理

D[i]表示错排列个数 , 可以证明

排列计数[luogu4071][逆元][错排列]_#define_02

然后预处理阶乘 , 查询时逆元搞一波就好了 (这年头用ex_gcd写逆元的真少) 


#include<bits/stdc++.h>
#define N 1000000
#define LL long long
#define P 1000000007
using namespace std;
LL C[N+50],D[N+50];
int T,n,m; LL x,y;
void exgcd(int a,int b){
if(!b){x=1,y=0; return;}
exgcd(b,a%b);
LL x1=y,y1=x-a/b*y;
x=x1,y=y1;
}
LL inv(int X){
int a=X,b=P; exgcd(a,b);
return (x+P)%P;
}
LL Ask(int x,int y){
return C[x] * inv(C[x-y]) % P * inv(C[y]) % P;
}
int main(){
C[0]=1 , D[0]=D[2]=1 , D[3]=2;
for(int i=1;i<=N;i++) C[i] = (LL)C[i-1] * i % P;
for(int i=4;i<=N;i++) D[i] = (LL)(i-1) * (D[i-1] + D[i-2]) % P;
scanf("%d",&T); while(T--){
scanf("%d%d",&n,&m);
printf("%lld\n",Ask(n,m) * D[n-m] % P);
}return 0;
}