错排 get !
何为错排?
所谓错排,即错位排列,意为对于
错排递推公式:
推导过程:
设现在有
首先,
然后,对于
如果
如果
由此可得递推公式。
模板:
传送门
int main(void)
{
cin >> n;
long long f[MAXN] = {0,0,1};
for(int i=3;i<=n;i++)
f[i] = (i-1)*(f[i-1]+f[i-2]);
cout << f[n] << endl;
return 0;
}
提高:
传送门
感觉这道题主要还是考的逆元的样子。。。(大概是我逆元学的不好?)
公式就不解释了,就是 (一眼题)
由于数据范围巨大,递推求组合数不是
所以需要预处理出阶乘的逆元,然后
一定要注意特判啊
int T;
int n,m;
long long ans;
long long num[MAXN],inv[MAXN]; //阶乘 及其 逆元
long long c[MAXN],d[MAXN];
long long FastPow(long long a, long long x)
{
long long ans = 1;
while(x)
{
if(x & 1) ans = ans*a%mod;
a = a*a%mod;
x >>= 1;
}
return ans;
}
void find_inv()
{
num[0] = 1;
for(int i=1;i<MAXN;i++)
{
num[i] = num[i-1]*i%mod;
inv[i] = FastPow(num[i],mod-2); //费马
}
d[0] = d[1] = 0; //错排
d[2] = 1;
for(int i=3;i<=MAXN;i++)
d[i] = (i-1)*(d[i-1]+d[i-2])%mod;
}
long long C(int n, int m)
{
if(m == 1) return n;
if(n == m) return 1;
return ((num[n]*inv[m])%mod*inv[n-m])%mod;
}
int main(void)
{
cin >> T;
find_inv();
for(int i=1;i<=T;i++)
{
scanf("%d%d",&n,&m);
if(n == m)
printf("1\n");
else if(n-m == 1)
printf("0\n");
else if(m == 0)
printf("%lld\n",d[n]);
else
printf("%lld\n",(C(n,m)*d[n-m])%mod);
}
return 0;
}