题意:告诉n个人排成一排,然后有m种颜色,要给这n个人正好涂k种颜色,相邻两个人颜色要不同,问有多少种方法。
分析:m种颜色选k种,所以有C(m,k),对于选出的k种颜色去给n个人涂色,对于第一个人有k种,第二个人有k-1种,第三个人k-1种。。。。。所以总共是k*(k-1)^(n-1)种。然而不要以为这样就好了,因为这样算并不能保证是一定用了k种颜色的,可能只是选了k种其中的2,3,4,,,,k-1种,所以要用容斥原理来去重,所以最后的式子就是
C(m,k) × ( k × (k-1)^(n-1) + ∑((-1)^p × C(k, p) × p × (p-1)^(n-1) ) (2 <= p <= k-1)。
#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
typedef long long ll;
const ll mod=1e9+7;
using namespace std;
ll in[1000100],cm[1000100],ck[1000100];
ll fun(ll m,ll n)
{
ll b=1;
while(n)
{
if(n&1)
b=b*m%mod;
n>>=1;
m=m*m%mod;
}
return b;
}
void init()//打表求逆元
{
in[1]=1;
for(ll i=2;i<=1000009;i++)
in[i]=(mod-mod/i)*in[mod%i]%mod;
}
ll n,m,k;
void fff()
{
cm[0]=ck[0]=1;
for(ll i=1;i<=k;i++)
{
cm[i]=cm[i-1]%mod*(m-i+1)%mod*in[i]%mod;
ck[i]=ck[i-1]%mod*(k-i+1)%mod*in[i]%mod;
}
}
int main()
{
int T;
init();
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
scanf("%lld%lld%lld",&n,&m,&k);
fff();//打表求组合数
printf("Case #%d: ",ca);
int tmp=1;
ll ans=0;
for(ll i=k;i>=1;i--)
{
ans=(ans+tmp*i*ck[i]%mod*fun(i-1,n-1)%mod+mod)%mod;
tmp=-tmp;
}
ans=ans*cm[k]%mod;
printf("%lld\n",ans);
}
return 0;
}