CF1342E Placing Rooks 题解

题面

第一个条件等价于:每一行都有车 / 每一列都有车。

不妨设每一行都有车,最后算答案时 ( imes 2) 即可。

有一个结论:如果恰好 (m) 列有车,那么就有 (n-m) 对车互相攻击。证明显然。

那么就可以知道恰好有 (n-k) 列有车。

于是考虑容斥,设在 (n-k) 列中有 (i) 列为空,则最终答案式子为:

[2 imesinom{n}{n-k} imessumlimits_{i=0}^{n-k}(-i)^i(n-k-i)^ninom{n-k}{i} ]

代码:

#include <bits/stdc++.h>
#define DC int T = gi <int> (); while (T--)
#define DEBUG fprintf(stderr, "Passing [%s] line %d
", __FUNCTION__, __LINE__)
#define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
#define fi first
#define se second
#define pb push_back
#define mp make_pair

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair <int, int> PII;
typedef pair <LL, LL> PLL;

template <typename T>
inline T gi()
{
	T x = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return f * x;
}

const int N = 200003, M = N << 1, mod = 998244353;

int n;
LL k;
int fac[N], invfac[N];

inline int qpow(int x, int y)
{
	int res = 1;
	while (y)
	{
		if (y & 1) res = 1ll * res * x % mod;
		x = 1ll * x * x % mod, y >>= 1;
	}
	return res;
}

inline int C(int x, int y)
{
	if (x < 0 || y < 0 || x < y) return 0;
	return 1ll * fac[x] * invfac[y] % mod * invfac[x - y] % mod;
}

int main()
{
	//freopen(".in", "r", stdin); freopen(".out", "w", stdout);
	n = gi <int> (), k = gi <LL> ();
	if (k >= n) return puts("0"), 0;
	for (int i = (fac[0] = 1); i <= n; i+=1) fac[i] = 1ll * fac[i - 1] * i % mod;
	invfac[n] = qpow(fac[n], mod - 2);
	for (int i = n - 1; i >= 0; i-=1) invfac[i] = 1ll * invfac[i + 1] * (i + 1) % mod;
	if (!k) return printf("%d
", fac[n]), 0;
	int sum = 0;
	for (int i = 0, t = 1; i <= n - k; i+=1, t *= -1)
	{
		int tmp = 1ll * qpow(n - k - i, n) * C(n - k, i) % mod;
		tmp *= t;
		(sum += tmp) %= mod;
	}
	(sum += mod) %= mod;
	sum = 2ll * sum % mod * C(n, n - k) % mod;
	printf("%d
", sum);
	return !!0;
}
原文地址:https://www.cnblogs.com/xsl19/p/15505549.html