1. 程式人生 > >UVALive 7040 F Color 容斥&組合數&快速冪&階乘逆元

UVALive 7040 F Color 容斥&組合數&快速冪&階乘逆元

Recently, Mr. Big recieved n owers from his fans. He wants to recolor those owers with m colors. The owers are put in a line. It is not allowed to color any adjacent owers with the same color. Flowers i and i + 1 are said to be adjacent for every i, 1 ≤ i < n. Mr. Big also wants the total number of different colors of the n owers being exactly k.

Two ways are considered different if and only if there is at least one ower being colored with different colors.

Input

The first line of the input gives the number of test cases, T. T test cases follow. T is 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 ≤ 109 , 1 ≤ k ≤ 106 , k ≤ n, m).

Output

For each test case, output one line containing ‘Case #x: y’, where x is the test case number (starting from 1) and y is the number of ways of different coloring methods modulo 109 + 7.

Sample Input

2

3 2 2

3 2 1

Sample Output

Case #1: 2

Case #2: 0

 

題目大意:

給n個連成一條線的塊上色,相鄰兩塊不能用同樣的顏色,並且恰好用所給m種顏色中的任意k種顏色上色。

 

一開始想的過於簡單了列出結果的式子是 C(k,m) * k * (k-1)^(n-1),但是這個式子裡包括用的顏色不足k種的情況,同時還有重複,可以說是很蠢很單純了。

後來,唉,那就容斥吧,好麻煩orz。

式子大概是這樣子的:

C(k,m) * ( k*(k-1)^(n-1) - C(1,k)*(k-1)*(k-2)^(n-1) + C(2,k)*(k-2)*(k-3)^(n-1) ... +(-1)^i * C(i,k)*(k-i)*(k-i-1)^(n-1) ...

組合數C(m,n) = n*...*(n-m+1)/m!;

求階乘逆元。還有快速冪。略。

注!因為有可能中間值有負數,所以累加的時候+mod再%mod!

 

#include<cstdio>
typedef long long ll;
const int maxk=1e6+5;
const ll mod=1e9+7;

ll fac[maxk],rev[maxk];

ll fast_pow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1){
            b--;
            ans=ans*a%mod;
        }
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
ll inv(ll a, ll n) {
    return fast_pow(a, mod-2);
}
void init()
{
     ll k=maxk-5;
     fac[0]=1;
     for(int i=1;i<=k;++i)
          fac[i]=fac[i-1]*i%mod;
     rev[k]=inv(fac[k],mod-2);
     for(int i=k-1;i>=0;--i)
          rev[i]=rev[i+1]*(i+1)%mod;
}
ll C(ll n,ll m){
    if(m<0)return 0;
    if(m>n-m)m=n-m;
    ll up=1,down=1;
    for(ll i=0;i<m;i++){
        up=up*(n-i)%mod;
        down=down*(i+1)%mod;
    }
    return up*inv(down,mod)%mod;
}

ll cal(ll k,ll n)
{
     ll ans=k*fast_pow(k-1,n-1);
     for(int i=1;i<k;++i){
          ll x=fac[k];
          x=x*rev[k-i]%mod*rev[i]%mod;
          x=x*(k-i)%mod*fast_pow(k-i-1,n-1);
          if(i&1) x=-x;
          ans=(ans+x+mod)%mod;
     }
     return ans;
}

int main()
{
    int t;
    ll n,m,k;
    init();
    scanf("%d",&t);
    for(int cas=1;cas<=t;++cas){
        scanf("%lld%lld%lld",&n,&m,&k);
        ll ans=C(m,k);
        ans=(ans*cal(k,n))%mod;
        printf("Case #%d: %lld\n",cas,ans);
    }
    return 0;
}