1. 程式人生 > >【組合數學 容斥原理】ICPC2014西安 F. Color

【組合數學 容斥原理】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;
}