Codeforces Gym 100548F Color (组合数+容斥)

78 篇文章 0 订阅
56 篇文章 0 订阅

2014西安区域赛的题,当时弱狗一条,2题gg

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


题目链接:http://codeforces.com/gym/100548/attachments


题目大意:直线上给n个物品染色,一共有m种颜色,求恰好用了k种颜色的染色方案数


题目分析:首先从m种颜色种选取k种颜色的方案为C(m,k),对于不超过的k种颜色的方案数很好求,为k*(k - 1)^(n - 1),第一个物品有k种选择,之后的n-1个物品因为不能和前面的相同,故都只有n-1种可能,但是题目要求的是恰好为k种的方案数,因此要容斥一下,容斥可以这样理解,假设不超过i种的方案数为F[i],那么其中包括了不超过i-1种的,不超过i-1种的里面又包含了不超过i-2种的,以此类推得到ans = F[k] - (F[k - 1] - (F[k - 2] - (... - (F[3] - F[2])))) = F[k] - F[k - 1] + F[k - 2] - ... + (-1)^(k - i)F[i]

因此最后答案为C(m,k)(Σ(-1)^(k - i)F[i]),其中F[i] = C(k,i)i*(i-1)^(n-1)

#include <cstdio>
#define ll long long
int const MOD = 1e9 + 7;
int const MAX = 1e6 + 5;
ll n, m, k, c[MAX], inv[MAX];

ll qpow(ll x, ll n)
{
    ll res = 1;
    while(n)
    {
        if(n & 1)
            res = (res * x) % MOD;
        x = (x * x) % MOD;
        n >>= 1;
    }
    return res;
}

void Init_inv()
{
    for(int i = 1; i < MAX; i++)
        inv[i] = qpow(i, MOD - 2);
}

void cal(ll n)
{
    c[0] = 1;
    for(int i = 1; i <= k; i++)
        c[i] = ((c[i - 1] * (n - i + 1) % MOD) * inv[i] % MOD) % MOD;
}

int main()
{
    Init_inv();
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ca++)
    {
        scanf("%I64d %I64d %I64d", &n, &m, &k);
        cal(k);
        ll ans = 0;
        int sign = 1;
        for(int i = k; i >= 1; i--, sign = -sign)
            ans = (ans % MOD + (sign * i * qpow(i - 1, n - 1)) % MOD * c[i] % MOD + MOD) % MOD;
        cal(m);
        printf("Case #%d: %I64d\n", ca, (ans % MOD * c[k] % MOD) % MOD);
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值