【Luogu】 P6076 [JSOI2015]染色问题

题目链接

点击打开链接

题目解法

可以一个一个条件考虑

  1. 只考虑条件 1 1 1
    答案即为 ( c + 1 ) n m (c+1)^{nm} (c+1)nm
  2. 考虑条件 1 , 2 1,2 1,2
    对每一行的方案数减去 1 1 1
    答案即为 ( ( c + 1 ) m − 1 ) n ((c+1)^m-1)^n ((c+1)m1)n
  3. 考虑条件 1 , 2 , 3 1,2,3 1,2,3
    考虑容斥
    容斥至少有 i i i 列未被染色,即为 g i g_i gi
    g i g_i gi n n n m − i m-i mi c c c 种颜色的方案数
    g i = ( ( c + 1 ) m − i − 1 ) n g_i=((c+1)^{m-i}-1)^n gi=((c+1)mi1)n
    答案即为 g 0 ∗ C m 0 − g 1 ∗ C m 1 + g 2 ∗ C m 2 − . . . g_0*C^0_m-g_1*C^1_m+g_2*C^2_m-... g0Cm0g1Cm1+g2Cm2...
  4. 考虑条件 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4
    继续考虑容斥
    先容斥至少有 j j j 种颜色未被用到,记为 f j f_j fj
    n n n m m m c − j c-j cj 种颜色的方案数
    这就是第 3 3 3 种情况的容斥
    直接搬来即可
    最终答案即为 f 0 ∗ C c 0 − f 1 ∗ C c 1 + f 2 ∗ C c 2 − . . . f_0*C^0_c-f_1*C^1_c+f_2*C^2_c-... f0Cc0f1Cc1+f2Cc2...

两次容斥时间复杂度 O ( m c ) O(mc) O(mc),求幂 O ( l o g n ) O(logn) O(logn)
总时间复杂度 O ( m c    l o g n ) O(mc\;logn) O(mclogn)

#include 
using namespace std;
typedef long long LL;
const int N(410),P(1e9+7);
int n,m,c,C[N][N]; 
inline int read(){
	int FF=0,RR=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
	for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
	return FF*RR;
}
int qmi(int a,int b){
	int res=1;
	for(;b;b>>=1){
		if(b&1) res=(LL)res*a%P;
		a=(LL)a*a%P;
	}
	return res;
}
int main(){
	n=read(),m=read(),c=read();
	C[0][0]=1;
	for(int i=1;i<N;i++)
		for(int j=0;j<=i;j++) C[i][j]=(!j||i==j)?1:(C[i-1][j]+C[i-1][j-1])%P;
	int ans=0;
	for(int i=0;i<=c;i++){//至少有i个颜色没出现 
		int res=0;
		for(int j=0;j<=m;j++){//至少有j列未染色 
			if(j&1) res=(res-(LL)qmi(qmi(c+1-i,m-j)-1,n)*C[m][j]%P+P)%P;
			else (res+=(LL)qmi(qmi(c+1-i,m-j)-1,n)*C[m][j]%P)%=P;
		}
		if(i&1) ans=(ans-(LL)res*C[c][i]%P+P)%P;
		else (ans+=(LL)res*C[c][i]%P)%=P;
	}
	printf("%d",ans);
	return 0;
}

你可能感兴趣的:(Luogu,c++)