引证:错排递推式:
f(n)=(f(n-1)+f(n-2))*(n-1)
试证:
f表示当前n个的错排。
当前选择n时,第一,对于位置k,互换则权值加上f(n-2)个错排,否则加上f(n-1)个错排。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define ll long long
inline void read(int &x){
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
const ll mod=1e9+7;
const ll N=1e6+10;
ll fac[N]={0};
ll f[N]={0};
ll quick_pow(ll sum,int x){
ll temp=1;
while(x){
if(x%2==1){
temp=temp*sum%mod;
}
sum=sum*sum%mod;
x/=2;
}
return temp;
}
ll inv(ll x){
return quick_pow(x,mod-2);
}
ll C(ll n,ll m){
ll x=fac[n];
ll y=fac[m]*fac[n-m]%mod;
y=inv(y);
return x*y%mod;
}
int main(){
f[0]=1;
f[1]=0;
for(int i=2;i<=1000010;i++){
f[i]=(i-1)*(f[i-1]+f[i-2])%mod;
}
fac[0]=1;
for(int i=1;i<=1000010;i++){
fac[i]=fac[i-1]*i%mod;
}
int T;
read(T);
// scanf("%d",&T);
while(T--){
int n,m;
read(n);
read(m);
// scanf("%d%d",&n,&m);
printf("%lld\n",C(n,m)*f[n-m]%mod);
}
}