【[SDOI2016]排列计数】

前言

这不是错排吗?!

诶,我怎么一眼就看出来了?

诶,我怎么打不来错排?

诶,我怎么躺地上了?

题目

洛谷

正题

\(m\) 个数字是对应的位置那么就有 \(C_n^m\) 种情况,剩下的数字只需要求出错排数,即求出 \(D(n-m)\),就搞定了

那么怎么求错排呢?前往博客食用:

错排

组合数就不用多说了吧,配合逆元求解

答案就是 \(C_n^m * D(n-m)\)

下面是丑陋的代码:

//12252024832524
#include 
#include 
#define Min(x,y) (xy?x:y)
using namespace std; 

typedef long long LL;
const int MAXN = 1000005;
const int MOD = 1e9 + 7;
int n,m;
LL cp[MAXN],inv[MAXN],jc[MAXN];//cp即错排,jc即阶乘

int Read()
{
	int x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
void Put(LL x)
{
	if(x > 9)
		Put(x/10);
	putchar(x%10^48);
}
void pre()
{
	cp[1] = 0;
	cp[2] = 1;
	jc[1] = 1;
	inv[0] = inv[1] = 1;
	for(int i = 3;i < MAXN;++ i)
		cp[i] = (i-1) * (cp[i-1] + cp[i-2]) % MOD;
	for(int i = 2;i < MAXN;++ i)
	{
		jc[i] = jc[i-1] * i % MOD;
		inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
	}
	for(int i = 1;i < MAXN;++ i)
		inv[i] = inv[i-1] * inv[i] % MOD;
	return;
}
LL C(int x,int y)
{
	return jc[x] * inv[y] % MOD * inv[x-y] % MOD;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	pre();
	for(int T = Read(); T ;-- T)
	{
		n = Read();
		m = Read();
		if(n == m)
			putchar('1');
		else
			Put(C(n,m) * cp[n-m] % MOD);
		putchar('\n');
	}
	return 0;
}

你可能感兴趣的:(【[SDOI2016]排列计数】)