大体题意:

给你n 个位置,你总共有m 种颜色,需要填满恰好填k种颜色且 相邻的位置的颜色不相同,问方案数,两个方案不同  区分为至少有一个位置的颜色的不同!

思路:

我们先选出k 种颜色来, 方案数  是  C(m,k)。

然后在n 个位置依次填,  第一个位置 有k 种情况,第二个位置 有k-1个情况  第三个位置有k-1个情况!这样就是

k*(k-1) ^ (n-1) 这些情况只是包含了两个相邻位置不相同,并不能保证恰好有k 种颜色!

这里用到了容斥定理,我们用总共k 种颜色的减去 k-1种颜色 的  即减去  (k-1) * (k-2) ^ (n-1),减去后并不是  答案!

因为减的时候会减多了,举一个例子:

假设你有4个位置, 让你填恰好 4种颜色!

假设让你在4种框子里涂4种颜色 ,恰好为4种!
那么你先用 4 * 3 * 3 * 3 总共四种颜色的情况 减去 三种颜色的   C(4,3) * 3 * 2 * 2 * 2
但这样会减多了两种的    比如是 一个减了 1 2 3  颜色    又减了 2 3 4  这样  2 3  这样两种颜色的就减多了!所以在加回来两种颜色的!  假设后面还有的化  这样就又多加了   1种颜色 的  再减去!  这样加一次减一次 。就是容斥定理了!

因此  答案就是    C(m,k) * (C(K,K) * K * (K-1) ^ (n-1) - c(k,k-1) * (k-1)*(k-2) ^(n-1) +....  c(k,1)*1*0^(n-1))

注意 枚举要枚举到1,因为可能 会只有1个位置的边界情况!

但是这样还没有完事!

求 k的多少次方 肯定是快速幂了!

k的范围很小  为100w,因此 为了加快速度,我们可以先预处理出来   c(m,k) 和 c(k,k)所有情况!

递推有除法,用到了逆元!

如果求逆元用快速幂的话,依然会超时!

虽然mod 很大,但是只用到了k 以内的数据!

因此 我们也可以预处理 递推求出逆元来!

详细见代码:


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mod = 1000000007;
const int maxn = 1000000 + 7;
ll my_pow(ll a,ll n){
    ll ans = 1ll;
    while(n){
        if (n & 1)
            ans = (ans * a) % mod;
        a = (a * a) % mod;
        n >>= 1;
    }
    return ans;
}
int n, m, k, ks, T;
ll ck[maxn], cm[maxn];
ll inv[maxn];
void initinv(){ // 递推求逆元
    inv[1] = 1;
    for (int i = 2; i < maxn; ++i) {
        inv[i] = (mod - mod/i) * inv[mod % i] % mod;
    }
}
void init(){
    ck[0] = cm[0] = 1; // 预处理所有的组合数!
    for (int i = 1; i <= k; ++i) {
        ck[i] = ((ck[i-1] * (k-i+1)) % mod * inv[i]) % mod;
        cm[i] = ((cm[i-1] * (m-i+1)) % mod * inv[i]) % mod;
    }
}
int main(){
    initinv();
    scanf("%d", &T);
    while(T--){
        scanf("%d %d %d", &n, &m, &k);
        init();
        if (n < k || m < k){
            printf("Case #%d: %d\n",++ks,0);
            continue;
        }
        ll ans = 0;
        for (int i = k, j = 1; i >= 1; --i,++j){ //  容斥定理的 枚举
            if (j & 1)
                ans = (ans + ((i * ck[i]) % mod * my_pow(i-1,n-1)) % mod + mod) % mod;
            else
                ans = (ans - ((i * ck[i]) % mod * my_pow(i-1,n-1)) % mod + mod) % mod;
        }
        ans = (ans * cm[k]) % mod;
        printf("Case #%d: %lld\n",++ks,ans);
    }
    return 0;
}