Color Gym - 100548F
原题链接
考察:容斥原理(二项式反演)
思路:
根据题意,定义\(g[i]\)为使用颜色不超过i种的方案数,这个比较好求,但是\(f[i]\)恰好为i个就比较难求.
但我们可以发现:
\[g[i] = C_i^0 f[0]+C_i^1 f[1] + C_i^2 f[2]+...+C_i^i f[i]
\]
这是标准的二项式反演式,根据二项式反演的定义,我们可以求到\(g[i]\),最后要乘上\(C_m^k\).
还有一种理解方式就是\(f[i]=g[i]-f[i-1]-f[i-2]..-f[1]\).这道题需要预处理.
Code
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int M = 1e9+7,N=1000010;
int n,m,k,fact[N],inv[N];
int qsm(int a,int k,int m)
{
int res = 1;
while(k)
{
if(k&1) res = (LL)res*a%M;
a = (LL)a*a%M;
k>>=1;
}
return res;
}
LL C(int a,int b)
{
if(a<b) return 0;
if(a<N&&b<N) return (LL)fact[a]*inv[a-b]%M*inv[b]%M;
int up = 1,down = 1;
for(int i=a,j=1;j<=b;i--,j++)
{
up = (LL)up*i%M;
down = (LL)down*j%M;
}
return (LL)up*qsm(down,M-2,M)%M;
}
void init()
{
fact[0] = 1,inv[0] = 1;
for(int i=1;i<N;i++)
{
fact[i] = (LL)fact[i-1]*i%M;
inv[i] = (LL)inv[i-1]*qsm(i,M-2,M)%M;
}
}
int main()
{
int T,kcase =0;
scanf("%d",&T);
init();
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
int res = 0;
for(int i=0;i<=k;i++)
{
int t = 1;
if(k-i&1) t*=-1;
res = res+(LL)t*C(k,i)*i%M*qsm(i-1,n-1,M)%M;
res%=M;
}
res = ((LL)res*C(m,k)%M+M)%M;
printf("Case #%d: %d\n",++kcase,res);
}
return 0;
}