题意:给定n朵花, 用m种颜色去染色, 要求相邻两朵花之间的颜色不同并且不同的颜色总数恰好为K,求方案数
分析:首先我们可以从m种颜色种选出k种颜色,让这k种颜色进行染色
g(k) : 恰好k种颜色的染色方案数
f(k):小于等于k种颜色的染色方案数
则 f(k) = sum(g(i) * c(k, i) (i = 1, 2, 3...k))
此处用到了二项式反演公式:则g(k) = sum((-1)^(k - i) * (k, i) * f(i) | (i = 1, 2, 3...k))
而f(i)的计算非常方便:f(k) = k * (k - 1) ^ (n - 1) % MOD;
#include
const int N = 1000000 + 5;
const int MOD = (int)1e9 + 7;
int n, m, K;
int inv[N];
// 逆元的计算
void prepare() {
inv[1] = 1;
for (int i = 2; i < N; i ++) {
inv[i] = 1ll * (MOD - MOD / i) * inv[MOD % i] % MOD;
}
}
inline void add(int& x, int y) {
x += y;
if (x >= MOD) {
x -= MOD;
} else if (x < 0) {
x += MOD;
}
}
int pow_mod(int x, int n) {
int ret = 1;
while (n) {
if (n & 1) {
ret = 1ll * ret * x % MOD;
}
x = 1ll * x * x % MOD;
n >>= 1;
}
return ret;
}
int f(int k, int n) {
return 1ll * k * pow_mod(k - 1, n - 1) % MOD;
}
int work() {
int ret = 0;
for (int i = 1, c = 1; i <= K; i ++) {
c = 1ll * (K - i + 1) * c % MOD * inv[i] % MOD;
int val = 1ll * c * f(i, n) % MOD;
if ((K - i) & 1) {
add(ret, -val);
} else {
add(ret, val);
}
}
for (int i = 1; i <= K; i ++) {
ret = 1ll * ret * (m - i + 1) % MOD * inv[i] % MOD;
}
return ret;
}
int main() {
prepare();
int t, ca = 1;
scanf("%d", &t);
while (t --) {
scanf("%d%d%d", &n, &m, &K);
printf("Case #%d: %d\n", ca ++, work());
}
return 0;
}