P4071 [SDOI2016]排列计数(全错排)

传送门

全错排递推为D[x]=(x-1)*(D[x-1]+D[x-2])
B站推导

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
#include<bitset>
#include<unordered_map>
using namespace std;
#define LL long long
#define eps (1e-9)
typedef unsigned long long ull;

const int maxn = 1e6 + 10;
const LL inf = 1e18;
const double pi = acos(-1.0);
const int bas = 131;
const LL mod = 1e9 + 7;

LL D[maxn + 10];
LL fac[maxn + 10], inv[maxn + 10];
LL qpow(LL a, LL b)
{
	LL res = 1;
	while (b)
	{
		if (b & 1)res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}
void init()
{
	fac[0] = inv[0] = 1;
	for (int i = 1; i <= maxn; i++)
	{
		fac[i] = fac[i - 1] * i % mod;
	}
	inv[maxn] = qpow(fac[maxn], mod - 2);
	for (int i = maxn - 1; i >= 1; i--)
	{
		inv[i] = inv[i + 1] * (i + 1) % mod;
	}
	D[1] = 0, D[2] = 1;
	for (LL i = 3; i <= maxn; i++)
	{
		D[i] = (i - 1) * (D[i - 1] + D[i - 2]) % mod;
	}
}
LL cal(int n, int m)
{
	if (n < m)return 0;
	else if (n == m)return 1;
	else return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
int main()
{
	init();
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int n, m;
		scanf("%d%d", &n, &m);
		if (n == m)printf("1\n");
		else if (m == 0)printf("%lld\n", D[n]);
		else if (m > n)printf("0\n");
		else
		{
			LL ans = cal(n, m) * D[n - m] % mod;
			printf("%lld\n", ans);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值