为什么又是结论题。
令
D
[
n
]
D[n]
D[n]为长度为
n
n
n的错排方案数。考虑增量法求
D
[
n
]
D[n]
D[n]。
假设已知
D
[
1
]
D[1]
D[1]~
D
[
n
−
1
]
D[n-1]
D[n−1]:
现在令所有元素有序排列好,即
a
[
i
]
=
i
a[i]=i
a[i]=i。
第
n
n
n个元素可以选择前
n
−
1
n-1
n−1个位置中的任意一个放进去,假设选了某个位置
k
k
k,那么这个位置的元素
k
k
k就被挤出来了。
如果
k
k
k放在了位置
n
n
n,现在就相当于是
n
n
n和
k
k
k交换了位置,剩下
n
−
2
n-2
n−2个元素需要错排。即为
D
[
n
−
2
]
D[n-2]
D[n−2]种方案。
如果
k
k
k不放在位置
n
n
n,相当于是把
a
[
k
]
!
=
k
a[k]!=k
a[k]!=k的限制变为了
a
[
n
]
!
=
k
a[n]!=k
a[n]!=k,由于
n
n
n的位置已经固定在
k
k
k,所以现在问题转化为了
1
1
1~
n
−
1
n-1
n−1的错排问题,方案数为
D
[
n
−
1
]
D[n-1]
D[n−1]。这
n
−
1
n-1
n−1个限制关系依然是一一对应的。
于是有: D [ n ] = ( n − 1 ) ∗ ( D [ n − 1 ] + D [ n − 2 ] ) D[n]=(n-1)*(D[n-1]+D[n-2]) D[n]=(n−1)∗(D[n−1]+D[n−2])
初始化: D [ 0 ] = 1 , D [ 1 ] = 0 , D [ 2 ] = 1 D[0]=1,D[1]=0,D[2]=1 D[0]=1,D[1]=0,D[2]=1
#include<bits/stdc++.h>
#define cs const
#define re register
cs int N=1e6+10,mod=1e9+7;
namespace IO{
cs int Rlen=1<<22|1;
char buf[Rlen],*p1,*p2;
inline char gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;}
template<typename T>
inline T get(){
char ch=gc();T x=0;
while(!isdigit(ch)) ch=gc();
while(isdigit(ch)) x=((x+(x<<2))<<1)+(ch^48),ch=gc();
return x;
}
inline int gi(){return get<int>();}
}
using IO::gi;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int quickpow(int a,int b,int ret=1){for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
int T,n,m,fac[N],ifac[N],D[N];
inline void prework(){
fac[0]=1;
for(int i=1;i<N;++i) fac[i]=mul(fac[i-1],i);
ifac[N-1]=quickpow(fac[N-1],mod-2);
for(int i=N-2;~i;--i) ifac[i]=mul(ifac[i+1],i+1);
D[1]=0,D[2]=1,D[0]=1;
for(int i=3;i<N;++i) D[i]=mul(i-1,add(D[i-1],D[i-2]));
}
inline int C(int n,int m){return (n<m)?0:mul(fac[n],mul(ifac[m],ifac[n-m]));}
int main(){
// freopen("2701.in","r",stdin);
prework(),T=gi();
while(T--) n=gi(),m=gi(),printf("%d\n",mul(C(n,m),D[n-m]));
}