ProblemF. Color
Description
Recently, Mr. Bigrecieved n flowers from his fans. He wants to recolor those flowerswith m colors. The flowers are put in a line. It is not allowed tocolor any adjacent flowers with the same color. Flowers i and
i + 1are said to be adjacent for every i, 1 ≤ i < n. Mr. Big alsowants the total number of different colors of the n flowers beingexactly k.
Two ways areconsidered different if and only if there is at least one flowerbeing colored
with differentcolors.
Input
The first line ofthe input gives the number of test cases, T. T test cases follow. Tis about 300 and in most cases k is relatively small.
For each test case,there will be one line, which contains three integers n, m, k (1 ≤n, m ≤ 10^9, 1 ≤ k ≤ 10^6, k ≤ n, m).
Output
For each test case,output one line containing “Case #x: y”, where x is the test casenumber (starting from 1) and y is the number of ways of differentcoloring methods modulo 10^9 + 7.
Samples
Sample Input |
Sample Output |
2 3 2 2 3 2 1 |
Case #1: 2 Case #2: 0 |
知识点:
组合数学-容斥原理,快速幂,逆元。
题目大意:
共有m
种颜色,为n盆排成一直线的花涂色。要求相邻花的颜色不相同,且使用的颜色恰好是k种。问一共有几种涂色方案(结果除10e9+7取余数)。
解题思路:
首先可以将m
与后面的讨论分离。从m
种颜色中取出k
种颜色涂色,取色部分有C(m, k)
种情况;
然后通过尝试可以发现,第一个有k种选择,第二个因不能与第一个相同,只有(k-1)
种选择,第三个也只需与第二个不同,也有(k-1)
种选择。总的情况数为k ×(k-1)^(n-1)。但这仅保证了相邻颜色不同,总颜色数不超过k种,并没有保证恰好出现k种颜色;
接着就是一个容斥问题,上述计算方法中包含了只含有2、3、…、(k-1)种颜色的情况,需要通过容斥原理去除。假设出现p
(2 <= p <= k-1)种颜色,从k种颜色中选取p种进行涂色,方案数为C(k,p)
× p × (p-1)^(n-1) ;
综上,最后的总方案数为C(m,k) × ( k × (k-1)^(n-1) +
∑((-1)^p × C(k, p) × p × (p-1)^(n-1) ) (2 <= p <= k-1);
最后,需要注意1 ≤ n, m ≤10^9,在进行指数运算时,需要使用快速幂。对于组合数,只需要计算C(m,k)和C(k,p)
(1 <= p <= k),可以采用递推法,即C[x,i] = C[x, i-1] * (n-i+1) / i,因为要取模,所以需要用到i的逆元。
参考代码:
#include <iostream> using namespace std; const int MOD = 1000000007; const int MAXN = 1000010; int nCase, cCase; long long n, m, k, ans1, ans2, C[MAXN]; inline long long pow_mod(long long p, long long k) { long long ans = 1; while (k) { if (k & 1) { ans = (ans * p) % MOD; } p = (p * p) % MOD; k >>= 1; } return ans; } inline long long inverse(long long num) { return pow_mod(num, MOD-2); } void calcC(long long n) { C[0] = 1; for (int i = 1; i <= k; i++) { C[i] = ((C[i-1] * (n-i+1)) % MOD) * inverse(i) % MOD; } } void solve() { calcC(m); ans1 = C[k]; calcC(k); ans2 = 0; int sgn = 1; for (int l = k; l >= 1; l--) { ans2 = (ans2 + (sgn * l * pow_mod(l-1, n-1)) % MOD * C[l] % MOD + MOD) % MOD; sgn = -sgn; } cout << "Case #" << ++cCase << ": " << ans1*ans2 % MOD << endl; } int main() { ios::sync_with_stdio(false); cin >> nCase; while (nCase--) { cin >> n >> m >> k; solve(); } return 0; }