题意:
求有多少种 (1) 到 (n) 的排列 (a),满足序列恰好有 (m) 个位置 ii,使得 (a_i=i),(T)组询问
答案对(10^9+7) 取模。
范围&性质:(1le Tle 10^5,1le n,mle10^6)
分析:
前置芝士:
错排的常见公式:
记 (f_i)表示 (i) 阶排列的个数,(g_i) 表示 (i) 阶错排的个数。
(n! = f_n =n sum C_n^igi)
于是可以解得
(g_i =n sum (−1)^{n−i}C_n^i fi =n sum (−1)^{n−i}C_n^i i!
= n!sum_{i=0}^n frac{(-1)^i}{i!})
由此还可以顺便求出它的递推式是:
(g_{n+1}= (n + 1)g_n + (−1)^{n+1}) 其初值是 (g_0 = 1)
对于这道题来说,先组合数从n个数中选择m个,再乘上错排
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
const int mod = 1e9+7;
const int maxn = 1e6+5;
int t,n,m;
long long inv[maxn],fac[maxn],per[maxn];
void init()
{
inv[1]=1;
fac[1]=1;
fac[0]=1;
for(int i=2;i<=1000000;i++)
{
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
fac[i]=fac[i-1]*i%mod;
}
inv[0]=1;
for(int i=1;i<=1000000;i++)
{
inv[i]=inv[i]*inv[i-1]%mod;
}
per[0]=1;
for(int i=1;i<=1000000;i++)
{
per[i]=(per[i-1]*i%mod+(i%2==1?-1:1))%mod;
}
}
long long C(int a,int b)
{
return fac[a]*inv[a-b]%mod*inv[b]%mod;
}
void work()
{
init();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
printf("%lld
",C(n,m)*per[n-m]%mod);
}
}
}
int main()
{
zzc::work();
return 0;
}