原题链接
题意:给你n个数其中这那个数的范围为1-n,如果第i个数a[i]的值为i则这个数是稳定的,那么当前给出n个数,如果恰好有m个数是稳定的,求满足序列的方案数
解法:第一步我们先选择出m个数是稳定的就是C(n,m),那么对于其他的n-m个数我们需要保证是错综排列的,对于这个错综排列的方案定义一个函数d[i],对于d[i]来说,d[i]的递推方程为d[i] = (d[i - 1] + d[i - 2])*(i - 1),那么我们求得答案就是C(n,m) * d[n-m]
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 2e6 + 5;
ll fact[maxn],inv[maxn];
ll d[maxn];
ll qpow(ll a, ll b , ll mod){
ll ans = 1;
while(b){
if(b & 1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init(){
fact[0] = fact[1] = 1;
for(int i = 2; i < maxn; i++){
fact[i]=fact[i-1]*i%mod;
}
inv[maxn - 1] = qpow(fact[maxn - 1],mod-2,mod);
for(int i = maxn-2; i >= 0; i--){
inv[i] = inv[i + 1]*(i+1)%mod;
}
d[0] = 1,d[1] = 0,d[2] = 1;
for(ll i = 3; i < maxn; i++){
d[i] = (d[i - 1] + d[i - 2])*(i - 1);
d[i] %= mod;
}
}
ll C(ll n, ll m, ll mod){
if(n < 0 || m < 0 || m > n)return 0;
if(m == 0 || m == n)return 1;
return fact[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
init();
int t;
scanf("%d",&t);
while(t--){
ll n,m;
scanf("%lld%lld",&n,&m);
ll ans = C(n,m,mod)*d[n-m]%mod;
printf("%lld\n",ans);
}
}