逐个去除限制。第四个限制显然可以容斥,即染恰好c种颜色的方案数=染至多c种颜色的方案数-染至多c-1种颜色的方案数+染至多c-2种颜色的方案数……
然后是限制二。同样可以容斥,即恰好选n行的方案数=至多选n行的方案数-至多选n-1行的方案数+至多选n-2行的方案数……
限制三同理。即容斥套容斥套容斥。复杂度O(nmc)。
注意到容斥式子和二项式定理有千丝万缕的联系,用二项式定理去掉一维变成O(nclogm)。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 410 #define P 1000000007 int n,m,c,ans,C[N][N]; void inc(int &x,int y){x+=y;if (x>=P) x-=P;} int ksm(int a,int k) { int s=1; for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P; return s; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4487.in","r",stdin); freopen("bzoj4487.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(),c=read(); C[0][0]=1; for (int i=1;i<=400;i++) { C[i][0]=C[i][i]=1; for (int j=1;j<i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%P; } for (int i=c;i>=0;i--) for (int j=n;j>=1;j--) if ((c-i+n-j+m&1)^(m&1)) inc(ans,P-1ll*C[c][i]*C[n][j]%P*ksm(ksm(i+1,j)-1,m)%P); else inc(ans,1ll*C[c][i]*C[n][j]%P*ksm(ksm(i+1,j)-1,m)%P); cout<<ans; return 0; }