ABC266 G(二项式反演)

题目链接

  题目大意:有\(a\)\(R,\ b个G,\ c个B\),要求出来恰好有\(k\)个连续的\(RG\)的排列方案数。
  思路:
    可以先将问题转化成至少有\(k\)\(RG\)的排列方案数有多少,然后可以用二项式反演的方法,将所有\(cnt_{RG} = k\)的方案数加起来就好了。二项式反演有这样的式子\(F(n) = \sum \binom{n}{i} D(i) \Rightarrow D(n) = \sum (-1) ^ {n - i} \binom{n}{i} F(i)\),那么我们将\(D(n)\)求出来就好了。

	int r, g, b, k;
	std::cin >> r >> g >> b >> k;
	int n = r + g + b;
	fac[0] = fav[0] = 1;
	for (int i = 1; i <= n; i++) fac[i] = 1LL * fac[i - 1] * i % mod; 
	fav[n] = power(fac[n], mod - 2);
	for (int i = n - 1; i >= 1; i--) fav[i] = 1LL * fav[i + 1] * (i + 1) % mod;
	
	auto C = [&](int n, int m) -> int {
		if (m > n || m < 0) return 0;
		return 1ll * fac[n] * fav[m] % mod * fav[n - m] % mod;
	};
	
	std::vector<int> f(n + 1);
	for (int i = 0; i <= std::min(r, g); i++) {
		int x = r - i, y = g - i;
		int m = x + y + i + b;
		f[i] = 1ll * C(m, i) * C(m - i, x) % mod * C(m - x - i, y) % mod * C(m - x - i - y, b) % mod;
	}
	
	int ans = 0;
	for (int i = k; i <= std::min(r, g); i++) {
		int p = ((i - k) & 1) ? -1 : 1;
		ans = (1ll * ans + mod + 1ll * p * C(i, k) % mod * f[i] % mod) % mod;
	}
	std::cout << ans << "\n";
posted @ 2022-09-06 10:16  浅渊  阅读(120)  评论(0)    收藏  举报