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;
}

posted @ 2021-06-15 00:43  acmloser  阅读(20)  评论(0编辑  收藏  举报