正解:dp+数论
解题报告:
考虑对每种颜色的棋子单独考虑鸭,那显然有,当某一行或某一列已经被占据的时候,那一行/一列就不能再放别的颜色的棋子了,相当于直接把那一行/一列直接消了
显然就能考虑到dp?设f[i][j]:剩余i行j列的方案数
转移就枚举这个颜色的棋子放了p行q列,设g[d][p][q]:d个棋子恰好放了p行q列的方案数
直接枚举pq,f[i][j]=∑f[i+p][j+1]*g[c[k]][p][q]
现在就只要知道怎么求g就好
看到这种恰好balabala的应该就第一反应想到容斥,,,?
这里也一样啊,就组合数算下容斥下就欧克辣!


#include<bits/stdc++.h> using namespace std; #define il inline #define ll long long #define gc getchar() #define ri register int #define rc register char #define rb register bool #define rp(i,x,y) for(ri i=x;i<=y;++i) #define my(i,x,y) for(ri i=x;i>=y;--i) const int mod=1000000009,N=30+10; int n,m,c,num[N],fac[N*N],ifac[N*N],g[N][N][N],f[N][N][N]={1},as; il int read() { rc ch=gc;ri x=0;rb y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:-x; } il int power(ri x,ri y){int ret=1;while(y){if(y&1)ret=1ll*ret*x%mod;x=1ll*x*x%mod;y>>=1;}return ret;} il void pre(ri n) { fac[0]=1;rp(i,1,n)fac[i]=1ll*fac[i-1]*i%mod; ifac[n]=power(fac[n],mod-2);my(i,n-1,0)ifac[i]=1ll*ifac[i+1]*(i+1)%mod; } inline int C(ri n,ri m){return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;} int main() { // freopen("3158.in","r",stdin);freopen("3158.out","w",stdout); n=read();m=read();c=read();rp(i,1,c)num[i]=read();pre(n*m); rp(i,1,c) { rp(j,1,n) { rp(k,1,m) { if(j*k<num[i])continue; g[i][j][k]=C(j*k,num[i]); rp(p,1,j)rp(q,1,k)if(p^j || q^k)g[i][j][k]=(g[i][j][k]+(mod-1ll*C(j,p)*C(k,q)%mod*g[i][p][q]%mod))%mod; } } } rp(i,1,c)rp(j,1,n)rp(k,1,m)rp(p,1,j)rp(q,1,k)f[i][j][k]=(f[i][j][k]+1ll*f[i-1][j-p][k-q]*g[i][p][q]%mod*C(n-j+p,p)%mod*C(m-k+q,q)%mod)%mod; rp(i,1,n)rp(j,1,m)as=(as+f[c][i][j])%mod;printf("%d\n",as); return 0; }