【组合数学 容斥原理】ICPC2014西安 F. Color

https://vjudge.net/contest/265252#problem/F

给你n朵花,m种颜色,k  (1 ≤ n, m ≤ 10^9 , 1 ≤ k ≤ 10^6 , k ≤ n, m)

花是一排,要求相邻花染色不能相同,染色数量刚好等于k,问你染色的方案数

如果用<=k种颜色,那么有k*(k-1)^(n-1)   *C(k,1)  种方案                ——A 

如果用<=k-1种颜色,那么有(k-1)*(k-2)^(n-1)    *C(k,2) 种方案       ——B

如果用<=k-2种颜色,那么有(k-2)*(k-3)^(n-1)    *C(k,3) 种方案       ——C

……

A方案包括了用k-1种颜色的要减去B,B中又包括了用k-2种颜色的要加上C

容斥原理!!!!

记得每一次要乘上C(k,i),因为减掉哪种颜色不确定

最后因为在m种颜色里选k种,*C(m,k)

又因为m<=1e^9,但是k<=1e^7,

所以用递推

记得容斥原理做的时候,减时先+mod,不然会出负的

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e9+7;
ll fac[1000005], inv[1000005];

ll quickpow(ll a, ll b)
{
    ll ret = 1;
    while(b)
    {
        if(b & 1) ret = (ret * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return ret;
}

void init(int p)
{
    fac[0] = 1;
    for(int i = 1; i <= p; i++)
        fac[i]=(fac[i - 1] * i) % mod;
    inv[p] = quickpow(fac[p], mod - 2);
    for(int i = p - 1; i >= 0; i--)
        inv[i] = (inv[i + 1] * (i + 1)) % mod;
}

ll C(ll n, ll m)
{
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

int main()
{
    int T, cas = 0;
    scanf("%d", &T);
    init(1000003);
    while(T --)
    {
        ll n, m, k;
        scanf("%lld%lld%lld", &n, &m, &k);
        ll ans = quickpow(k - 1, n - 1) * k % mod;
        for(int i = 1; i < k - 1; i++)
        {
            ll sum = quickpow(k - i - 1, n - 1) * (k - i) %mod * C(k , i) % mod;
            if(i & 1) ans = (ans - sum + mod) % mod;
            else ans = (ans + sum) % mod;
        }

        for(int i = m - k + 1; i <= m; i++)
        {
            ans = ans * i % mod;
        }
        ans = ans * inv[k] % mod;
        printf("Case #%d: %lld\n", ++cas, ans);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_41037114/article/details/83385359
今日推荐