2014西安F题

题意:给定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;
}
   
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值