UVALive 7040 Color(容斥)

题目

链接1

链接2


题意:n个格子,m种颜色,取k种颜色,恰好使用k种颜色为n个格子上色,相邻格子颜色不同,求方案数,对1e9+7取余。


c(m,k)×k×(k-1)^n-1,这是少于k种颜色上色的情况,不是恰好。
假设出现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);


#include 
#include 
#include 
#include 
using namespace std;
#define ll long long
const int N = 1e6+5;
const int mod = 1e9+7;
ll cm[N], ck[N], inv[N];
ll t, n, m, k;
ll quick_pow(ll a, ll b)///快速幂
{
    ll ans = 1;
    while(b){
        if(b & 1) ans = ans*a%mod;
        b >>= 1;
        a = a*a%mod;
    }
    return ans;
}
void get_inv()///逆元
{
    for(int i=1; imod-2);///
    }
}
void get_c()///c(m,i) && c(k,i)
{
    cm[0] = ck[0] = 1;
    for(int i=1; i<=k; i++){///
        cm[i] = cm[i-1]%mod * (m-i+1)%mod * inv[i]%mod;///m-i+1
        ck[i] = ck[i-1]%mod * (k-i+1)%mod * inv[i]%mod;
    }
}

int main()
{
    get_inv();//printf("inv %lld\n", inv[2]);
    scanf("%d", &t);
    for(int cnt=1; cnt<=t; cnt++){
        scanf("%d%d%d", &n, &m, &k);
        get_c();
        ll sign = 1, ans = 0;
        for(int i=k; i>=1; i--){
            ans = (ans+sign*ck[i]%mod*i%mod*quick_pow((ll)i-1, (ll)n-1)%mod+mod)%mod;
            sign = -sign;///奇加偶减
        }
        ans = ans*cm[k]%mod;///m选k个
        printf("Case #%d: %lld\n", cnt, ans);
    }
    return 0;
}

你可能感兴趣的:(组合数学)