2015 asia xian regional F Color (容斥 + 组合数学)

2015 asia xian regional F Color (容斥 + 组合数学)

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

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.

Sample Input

2
3 2 2
3 2 1

Sample Output

Case #1: 2
Case #2: 0

题意:

给你n个物品,最多有m种颜色可以使用,你需要把这n个物品染色,要求恰好使用k种颜色。问不同的染色方案数

题解:

首先我们需要使用k种颜色,那么就是在m种选择k种,然后第一个物品可以染k种颜色,后面每个可以染k-1种颜色,那么就是C(m,k)C(k,k)k*(k-1)^(n-1)。但是这个是最多使用k种颜色,不是恰好使用k种颜色,这时候就使用容斥了。首先这个结果包含了最多k-1种颜色的结果,最多k-1种种又包含了最多k-2种,这个时候我们就可以利用容斥的奇加偶减来计算从k~1。
求组合数可以使用逆元打表求得。至于组合数公式是很简单的求法。

代码:

#include <bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const ll mod = 1e9+7 ;
const int maxn = 1e6 + 10 ;
ll pow(ll a, ll n)
{
    ll ret = 1, cal = a ;
    while (n){
        if (n&1)
            ret = ret*cal%mod ;
        cal = cal*cal%mod ;
        n >>= 1;   
    }    
    return ret ;
}

ll inv[maxn] ;
void getinv()
{
    for (ll i = 1; i < maxn; i++)
        inv[i] = pow(i,mod-2) ;
}

ll co[maxn] ;
void comb(ll n, ll k)
{
    co[0] = 1;
    for (ll i = 1; i <= k; i++)    
        co[i] = ((co[i-1] * (n-i+1)%mod) * inv[i])%mod ;
}

ll solve(ll n, ll m, ll k)
{
    comb(k,k) ; 
    ll sign = 1;
    ll ans = 0;
    for (long long i = k; i >= 1; i--){
        ans = (mod + ans + ((sign*co[i]%mod)*i%mod)*pow(i-1,n-1)%mod)%mod ;
        sign = -sign ;
    }
    comb(m,k) ;
    ans = ans*co[k]%mod ;
    return ans ;
}

int main()
{
    getinv() ;
    int t;
    scanf("%d",&t) ;
    for (int _t = 1; _t <= t; _t++){
        ll n,m,k; 
        scanf("%lld %lld %lld",&n,&m,&k) ;   
        printf("Case #%d: %lld\n",_t,solve(n,m,k)) ;
    }
    return 0 ;
}
posted @ 2016-10-09 20:48 Thecoollight 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/thecoollight/p/5943727.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值