有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 long const 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; }