题目大意: 问有多少个 1 1 1 ~ n n n 的排列,恰好有 m m m 个位置满足 a i = i a_i=i ai=i。
题解
显然剩下的 n − m n-m n−m 个位置都不满足 a i = i a_i=i ai=i,那么就是个错排问题了,再乘上 C n m C_n^m Cnm 选择一下 a i = i a_i=i ai=i 的位置即可。
还要特判一下 n − m = 1 n-m=1 n−m=1 和 n − m = 0 n-m=0 n−m=0 的情况( n − m = 0 n-m=0 n−m=0 的情况我用 D [ 0 ] = 1 D[0]=1 D[0]=1 来解决了)。
代码如下:
#include <cstdio>
#define maxn 1000010
#define mod 1000000007
int T,n,m;
int fac[maxn],inv_fac[maxn],D[maxn];
int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;x=1ll*x*x%mod,y>>=1);return re;}
#define inv(x) ksm(x,mod-2)
void work()
{
fac[0]=inv_fac[0]=1;
for(int i=1;i<=maxn-10;i++)fac[i]=1ll*fac[i-1]*i%mod;
inv_fac[maxn-10]=inv(fac[maxn-10]);
for(int i=maxn-11;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
D[0]=D[2]=1;for(int i=3;i<=maxn-10;i++)D[i]=1ll*(D[i-1]+D[i-2])%mod*(i-1)%mod;
}
int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
int main()
{
work();scanf("%d",&T);while(T--)
{
scanf("%d %d",&n,&m);
if(n-m==1)printf("0\n");
else printf("%d\n",1ll*C(n,m)*D[n-m]%mod);
}
}