bzoj4487: [Jsoi2015]染色问题(容斥原理)

传送门
题意简述:
c c c中颜色给一个 n ∗ m n*m nm的方格染色,每个格子可涂可不涂,问最后每行每列都涂过色且 c c c中颜色都出现过的方案数。


思路:
f i , j , k f_{i,j,k} fi,j,k表示至少 i i i行没涂色,至少 j j j列没涂色,至少 c c c种颜色没涂色的方案数。
于是 f i , j , k = C n i C m j C c k ( c − k + 1 ) ( n − i ) ( m − j ) f_{i,j,k}=C_n^iC_m^jC_c^k(c-k+1)^{(n-i)(m-j)} fi,j,k=CniCmjCck(ck+1)(ni)(mj)
容斥一下即可。
注意算最后一项的时候每次先预处理。
代码:

#include
#define ri register int
using namespace std;
typedef long long ll;
const int N=405,mod=1e9+7,mod1=1e9+6;
int ans=0,fac[N],ifac[N],n,m,c,a[N],mult[N*N];
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline int C(int n,int m){return mul(mul(fac[n],ifac[m]),ifac[n-m]);}
inline void init(){
	int up=max(n,max(m,c));
	fac[0]=fac[1]=ifac[0]=ifac[1]=1;
	for(ri i=2;i<=up;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[mod-mod/i*i],mod-mod/i);
	for(ri i=2;i<=up;++i)ifac[i]=mul(ifac[i],ifac[i-1]);
}
int main(){
	freopen("lx.in","r",stdin);
	cin>>n>>m>>c;
	init();
	for(ri k=0,tmp;k<=c;++k){
		mult[0]=1;
		for(ri i=1;i<=n*m;++i)mult[i]=mul(mult[i-1],c-k+1);
		for(ri i=0;i<=n;++i)for(ri j=0;j<=m;++j){
			tmp=mul(mul(C(n,i),C(m,j)),mul(C(c,k),mult[(n-i)*(m-j)]));
			ans=(i+j+k)&1?dec(ans,tmp):add(ans,tmp);
		}
	}
	cout<<ans;
	return 0;
}

你可能感兴趣的:(#,容斥原理,#,数学)