题目:题目链接
分析:
显然,就是在字符串中选择m个数,再将剩下的数进行错位排序。记录这个题的原因就是记一下逆元(链接)和错位排序公式。简单的排列组合可以得到,答案就是
代码:
#include<bits/stdc++.h>
using namespace std;
#define MOD 1000000007
int t,n,m;
long long fac[1000005],inv[1000005],D[1000005];
long long C(int n,int m) {//n>=m,计算组合数
if(n<m) return 0;
if (m==n||m==0) return 1;
long long ans=((fac[n]*inv[m])%MOD*inv[n-m])%MOD;//除等于乘逆元
return ans;
}
long long ksm(long long base,long long power) {//快速幂
long long ans=1;
while (power) {
if (power&1) ans=(ans*base)%MOD;
base=(base*base)%MOD;
power>>=1;
}
return ans%MOD;
}
void init() {
D[0]=0;
D[1]=0;
D[2]=1;
for (int i=3;i<1000005;i++) D[i]=(i-1)*(D[i-1]+D[i-2])%MOD;//将错排数打表
fac[0]=1;
inv[0]=1;
for (int i=1;i<=(1000002);i++) {
fac[i]=(fac[i-1]*i)%MOD;//算阶乘
}
inv[1000001]=ksm(fac[1000001],MOD-2);//算逆元
for (int i=1000000;i>=1;i--)inv[i]=(inv[i+1]*(i+1))%MOD;//递推算逆元
}
int main() {
init();
cin>>t;
while(t--) {
cin>>n>>m;
long long ans=C(n,m)%MOD;
if (n!=m)ans=(ans*D[n-m])%MOD;
cout<<ans<<endl;
}
}