首先真诚地感谢BZ某大神为我们解锁正确的备考姿势。一语惊醒梦中人。
回到题目。。。不难看出一答案ans=D[n-m]*C(m,n);,其中D是错位排序数,也就是n个数全排列中,满足ai!=i的排列的个数,具体证明涉及到容斥原理。存在递推公式。
为了计算C,我们可以将n! mod p以及 (n!) ^ -1 mod p 全部预处理出来,两个操作均存在线性递推。
然后答案就可以在O(1)内求解了。。。
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define mo 1000000007
#define maxn 1000005
long long jie[maxn],inv[maxn],D[maxn];
void ready()
{
jie[0]=jie[1]=1;for(int i=2;i<=1000000;i++)jie[i]=(jie[i-1]*i)%mo;
inv[0]=inv[1]=1;for(int i=2;i<=1000000;i++)inv[i]=(mo-(mo/i))*inv[mo%i]%mo;
for(int i=2;i<=1000000;i++)inv[i]=(inv[i-1]*inv[i])%mo;
D[0]=1;D[1]=0;D[2]=1;for(int i=2;i<=1000000;i++)D[i]=(D[i-1]+D[i-2])*(i-1)%mo;
return ;
}
int T;
long long n,m,ans;
void _readLL(long long &x)
{
x=0; char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return ;
}
char s[35];int cc;
void out(long long x)
{
if(x==0)putchar('0');
cc=0; while(x){cc++; s[cc]=x%10+'0';x=x/10;}
while(cc){putchar(s[cc]);cc--;}
return ;
}
int main()
{
freopen("in.txt","r",stdin);
ready();
scanf("%d",&T);
while(T--)
{
_readLL(n);_readLL(m);
ans=(D[n-m]*jie[n])%mo;
ans=ans*inv[m]%mo*inv[n-m]%mo;
if(m<=n)out(ans);
if(T)putchar('\n');
}
return 0;
}