Description
有n*m的网格图和c种颜色,问有多少种涂色方法满足:
- 每一列至少有一个格子被涂色
- 每一行至少有一个格子被涂色
- 每一种颜色至少被用了一次
- 每一个格子要么被染色(1种),要么不被染色
n,m,c≤400n,m,c\le 400n,m,c≤400
Solution
很显然我们有∑i=0n∑j=0m∑k=0c(−1)n−i+m−j+c−k(ni)(mj)(ck)(k+1)ij\sum_{i=0}^n\sum_{j=0}^m\sum_{k=0}^c{{\left(-1\right)}^{n-i+m-j+c-k}\binom{n}{i}\binom{m}{j}\binom{c}{k}{\left( k+1\right)}^{ij}}i=0∑nj=0∑mk=0∑c(−1)n−i+m−j+c−k(in)(jm)(kc)(k+1)ij
然后nmc才400^3,我们交换枚举顺序然后预处理一下次幂就可以O(n3)O(n^3)O(n3)过了,注意提一下公因式保证膜的次数比较少
贴一下化简的n2logn做法吧
二项式定理有(x−1)k=∑i=0kxi(−1)k−j(ki)\left(x-1\right)^k=\sum_{i=0}^k{x^i{(-1)}^{k-j}\binom{k}{i}}(x−1)k=i=0∑kxi(−1)k−j(ik)
我们可以把柿子化成∑i=0n∑k=0c(−1)n+c−i−k(ni)(ck)∑j=0m(mj)((k+1)i)j(−1)m−j\sum_{i=0}^n\sum_{k=0}^c(-1)^{n+c-i-k}\binom{n}{i}\binom{c}{k}\sum_{j=0}^m\binom{m}{j}{\left({\left(k+1\right)}^i\right)}^j{(-1)}^{m-j}i=0∑nk=0∑c(−1)n+c−i−k(in)(kc)j=0∑m(jm)((k+1)i)j(−1)m−j
然后发现最右边和上柿是一样的形式,套进去就是
∑i=0n∑k=0c(−1)n+c−i−k(ni)(ck)((k+1)i−1)m\sum_{i=0}^n\sum_{k=0}^c(-1)^{n+c-i-k}\binom{n}{i}\binom{c}{k}{\left({\left(k+1\right)}^i-1\right)}^mi=0∑nk=0∑c(−1)n+c−i−k(in)(kc)((k+1)i−1)m
然后直接做就阔以了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
typedef long long LL;
const int MOD=1000000007;
const int N=405;
LL inv[N],fac[N],pow[N*N];
void upd(LL &x,LL v) {
x+=v; (x>=MOD)?(x-=MOD):0;
}
int main(void) {
freopen("data.in","r",stdin);
fac[0]=fac[1]=1;
rep(i,2,N-1) fac[i]=fac[i-1]*i%MOD;
inv[0]=inv[1]=1;
rep(i,2,N-1) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
rep(i,2,N-1) inv[i]=inv[i-1]*inv[i]%MOD;
int n,m,c; scanf("%d%d%d",&n,&m,&c);
LL ans=0;
rep(k,0,c) {
pow[0]=1;
rep(i,1,n*m) pow[i]=pow[i-1]*(k+1)%MOD;
LL wjp=0;
rep(i,0,n) {
LL xjh=0;
rep(j,0,m) {
LL tmp=inv[j]*inv[m-j]%MOD*pow[i*j]%MOD;
if ((n-i+m-j+c-k)&1) upd(xjh,MOD-tmp);
else upd(xjh,tmp);
}
upd(wjp,inv[n-i]*xjh%MOD*inv[i]%MOD);
}
upd(ans,wjp*fac[n]%MOD*fac[c]%MOD*inv[k]%MOD*inv[c-k]%MOD*fac[m]%MOD);
}
printf("%lld\n", ans);
return 0;
}