大意:有一排一共n个珠子,要用m种颜色中的恰好k种去涂色,相邻的两个颜色要不同,问方案数。
做法大概就是C(m,k)表示m中k种颜色,然后对于每k个颜色进行容斥(大概就是这样)
代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <string.h>
#include <cstdio>
#include <map>
#include <queue>
#include <math.h>
#include <cstring>
#include <set>
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const LL MOD=1e9+7;
const double eps=1e-9;
const LL MAXN=1000000+23;
LL quick(LL x,LL a)
{
LL res=1;
while(a)
{
if(a&1)res=res*x%MOD;
a>>=1;
x=x*x%MOD;
}
return res%MOD;
}
LL n,m,k;
LL jk[1000000+23],jm[1000000+23],jk1[1000000+23],nk[1000000+23];
LL C(LL a,LL b)
{
if(a==b||b==0)return 1;
LL r=nk[b];
return r*jm[b]%MOD;
}
LL C1(LL a,LL b)
{
if(a==b||b==0)return 1;
LL r=nk[b];
return r*jk1[b]%MOD;
}
int main()
{
jk[0]=1;
for(int i=1;i<=1000000+3;i++)
{
jk[i]=jk[i-1]*i;
jk[i]%=MOD;//k的阶乘
nk[i]=quick(jk[i],MOD-2);//阶乘对应的逆元
}
int T;
int cas=0;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&m,&k);
jm[0]=1;jk1[0]=1;
for(int i=1;i<=k;i++)
{
jk1[i]=jk1[i-1]*(k-i+1);
jk1[i]%=MOD;//k*(k-1)*...*(k-i+1)
jm[i]=jm[i-1]*(m-i+1);
jm[i]%=MOD;//m*(m-1)*...*(m-i-1),用来求组合数的
}
//printf("%lld %lld\n" ,C(6,4),C(6,3));
//printf("***%lld\n",jk1[2]);
LL ans=k*quick(k-1,n-1)%MOD;//最多用k种进行涂色,注意是最多,不是恰好
//printf("ans=%lld\n",ans);
int s=-1;
for(int i=k-1;i>=2;i--)//对k容斥
{
LL res=C1(k,i)*i%MOD*quick(i-1,n-1);
res%=MOD;
//else res=C1(k,i)*i*quick(i-1,n-1);
//printf("res=%lld\n",res);
ans+=res*s;
s*=-1;
ans%=MOD;
}
ans=ans*C(m,k)%MOD;
//printf("C=%lld\n",C(m,k));
printf("Case #%d: %lld\n",++cas,(ans%MOD+MOD)%MOD);
}
return 0;
}
额(⊙o⊙)…...大概就是酱紫了,如果有错误请指正,当然没有错误是坠吼的(害怕.jpg).....