2014-2015 ACM-ICPC, Asia Xian Regional Contest F Color

来源:互联网 发布:csi网络分集剧情 编辑:程序博客网 时间:2024/04/28 00:13

Color

        有n朵花排成一列,m种颜色,给这些花染色,使得恰好有k种颜色,且相邻的花颜色不同,问有多少种染色法。

        首先必须从m种颜色中选出k种,这部分有C(m,k)种选法。然后第一朵花可以染成k种颜色,后面的所有花都能染成k-1种颜色,也就是k*(k-1)*...*(k-1)。但是这样不能保证整个过程中k种颜色全部用到了。于是需要根据容斥原理做一下处理,减去用了k-1种颜色的情况,加上用了k-2种颜色的情况......另外计算过程中用到了组合数,可以逆元+暴力计算出来。


#include <bits/stdc++.h>using namespace std;#define ll long longconst int mod = 1e9+7;const int maxk = 1000010;ll fac[maxk];ll inv[maxk];ll Pow(ll a,int n){    ll re=1;    while(n){        if(n&1){            re*=a;            re%=mod;        }        a*=a;        a%=mod;        n>>=1;    }    return re;}//组合数ll C(int n,int k){    if(n<=1000000){        ll res=fac[n]*inv[k];        res%=mod;        res*=inv[n-k];        res%=mod;        return res;    }    ll res=inv[k];    for(int i=0;i<k;i++){        res*=(n-i);        res%=mod;    }    return res;}void init(){    fac[0]=1;    for(int i=1;i<maxk;i++){        fac[i]=fac[i-1]*i;        fac[i]%=mod;    }    inv[0]=1;   //注意这个不能漏    for(int i=1;i<maxk;i++){//费马小定理计算阶乘的逆元        inv[i]=Pow(fac[i],mod-2);    }}int main(){    init();    int t;    cin>>t;    int cas=0;    while(t--){        cas++;        ll n,m,k;        cin>>n>>m>>k;        ll part1 = C(m,k);        ll part2 = k*Pow(k-1,n-1);        part2%=mod;        int sign = -1;        for(ll i=k-1;i>1;i--){            ll tmp = i*Pow(i-1,n-1);            tmp%=mod;            tmp*=C(k,i);            tmp%=mod;            tmp*=sign;            part2+=tmp;            part2+=mod;            part2%=mod;            sign=-sign;        }        ll ans = part1*part2;        ans %= mod;        printf("Case #%d: ",cas);        cout<<ans<<endl;    }    return 0;}


0 0
原创粉丝点击