【UVALive-7040F】Color

题目大意:给定一个长度为 N 的序列,现有 M 种颜色,选出一些颜色对这个序列进行染色,要求相邻元素颜色不相同。求最终序列恰好有 K 种不同颜色的染色方案数,结果对1e9+7取模。

题解:二项式反演

代码如下

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const LL mod = 1e9 + 7;
const int maxn = 1e6 + 10;

LL fpow(LL a, LL b) {
	LL ret = 1 % mod;
	for (; b; b >>= 1, a = a * a % mod) {
		if (b & 1) {
			ret = ret * a % mod;
		}
	}
	return ret;
}

LL fac[maxn], ifac[maxn];

void prework() {
	int n = 1e6;
	fac[0] = fac[1] = 1;
	for (int i = 2; i <= n; i++) {
		fac[i] = fac[i - 1] * i % mod;
	}
	ifac[n] = fpow(fac[n], mod - 2);
	for (int i = n - 1; i >= 0; i--) {
		ifac[i] = ifac[i + 1] * (i + 1) % mod;
	}
}
inline LL comb1(int x, int y) {
	if (y > x) {
		return 0;
	}
	return fac[x] * ifac[x - y] % mod * ifac[y] % mod;
}
inline LL comb2(int x, int y) {
	if (y > x) {
		return 0;
	}
	LL ret = 1;
	for (int i = x; i >= x - y + 1; i--) {
		ret = ret * i % mod;
	}
	return ret * ifac[y] % mod;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	prework();
	int T, kase = 0;
	cin >> T;
	while (T--) {
		int n, m, K;
		cin >> n >> m >> K;
		auto f = [&](int x) {
			LL ret = x;
			return ret * fpow(x - 1, n - 1) % mod;
		};
		LL ans = 0;
		if (K == 1) {
			ans = (n == 1) ? 1 : 0;
		} else {
			for (int i = 1; i <= K; i++) {
				if ((K - i) & 1) {
					ans = (ans - comb1(K, i) * f(i) % mod + mod) % mod;
				} else {
					ans = (ans + comb1(K, i) * f(i) % mod) % mod;
				}
			}	
		}
		cout << "Case #" << ++kase << ": " << ans * comb2(m, K) % mod << endl;
	}
	return 0;
}
posted @ 2019-10-07 23:24  shellpicker  阅读(211)  评论(0编辑  收藏  举报