您的位置:首页 > 其它

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

2017-10-13 20:04 267 查看
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(这里可以这样理解,第n个位置有k种染法,剩下k-1种颜色染n-1个位置方案数(k-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),特殊处理一下n!=1且k=1时候情况为0,还有就是注意一下中间过程可能为负数情况,需要+mod再%mod;

当然,下面代码写的是这种写法,还有一种写法直接给出公式了:ans=C(m,k)(Σ(-1)^(i)f[i]),其中f[i]=C(k,i)(k-i)*(k-i-1)^(n-1);
代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const LL mod = 1e9 + 7;

const int maxn = 1e6 + 5;

LL sum1[maxn],sum11[maxn];

LL inv[maxn],C[maxn];

LL n, m, k,pri[maxn],ni[maxn];

LL poww(LL a, LL k, LL s)

{

    LL ans = 1;

    while(k)

    {

        if(k & 1)ans = ans * a % s;

        a = a * a % s;

        k /= 2;

    }

    return ans;

}

void niyuan()

{

    inv[1]=1;

    for(int i=2;i<maxn;i++)

    {

        inv[i] = (mod - mod/i) * inv[mod%i] % mod;

    }

}

void init()   //打表

{

    pri[0]=1;

    ni[0]=1;

    for (int i=1;i<maxn ;i++)

    {

        pri[i]=pri[i-1]*i%mod;  //N!

        ni[i]=poww(pri[i],mod-2,mod);

    }

}

LL c(LL m,LL k)

{

    LL res=1;

    k=min(k,m-k);

    for(int i=0;i<k;i++)

    {

        res=res*(m-i)%mod;

    }

    for(int i=0;i<k;i++)

    {

        res=res*inv[i+1]%mod;

    }

    return res;

}//C(m,k)

int main()
{

    int T;

    niyuan();

    init();

    scanf("%d",&T);

    while(T--)

    {

        static int t = 1;

        scanf("%lld%lld%lld", &n, &m, &k);

        if(n != 1 && k == 1)

        {

            printf("Case #%d: 0\n",t++);

            continue;

        }

        LL sum = c(m, k); //Cmk

        LL ans = 0, sum3;

        for(LL i = 0; i <= k; i++) sum1[i] = 0;

        for(LL i = 0; i <= k; i++)

        {

            LL sum=((pri[k]*ni[i]%mod)*ni[k-i])%mod;//C(k,i)

            sum1[i]=sum;

        }

        for(LL i = 0; i <= k; i++) sum11[i] = (poww(i - 1, n - 1, mod) + mod) % mod;

        for(LL i = 0; i <= k; i++)

        {

            LL sum2 = sum11[i];

            sum2 = (sum2 * i + mod) % mod;

            if((k-i) & 1) sum3 = -1;

            else sum3 = 1;

            sum1[i] = (sum1[i] * sum2 + mod) % mod;

            sum1[i] = (sum1[i] * sum3 + mod) % mod;

            ans = (ans + sum1[i]) % mod;

        }

        ans = (ans * sum) % mod;

        printf("Case #%d: %lld\n", t++, ans);

    }

    return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces