题目大意
一个
n×m
的网格图,
K
种颜色,我们要用
共有
T
组询问,给定
1≤T≤104,1≤n,m≤20,1≤K≤50
题目分析
既然要求曼哈顿距离为奇数,那我们考虑对网格图黑白染色,那么同色方格的只能分配在同一个集合里面。
为了不重复计数,考虑枚举严格用了
i
种颜色,我们再枚举分配
其中
fi,j
为第二类斯特林数,表示将
i
个数分配到
fi,j=fi−1,j−1+fi−1,j×jf0,i=0i
这些东西都可以预处理。
注意边界要开好,不然 n=1,m=1 情况会错。
时间复杂度 O(n2m2+qK2) 。
代码实现
#include <iostream>
#include <cstdio>
#include <cctype>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int P=1000000007;
const int N=20;
const int M=20;
const int S=N*M;
const int K=50;
bool col[N+2][M+2];
int f[S+2][K+2];
int c[S+2][S+2];
int fact[S+2];
int n,m,s1,s2,k,T,ans;
void pre()
{
f[0][0]=1;
for (int i=1;i<=S;i++)
for (int j=1;j<=K&&j<=i;j++)
f[i][j]=(1ll*f[i-1][j]*j+f[i-1][j-1])%P;
fact[0]=1;
for (int i=1;i<=S;i++) fact[i]=1ll*fact[i-1]*i%P;
c[0][0]=1;
for (int i=1;i<=S;i++)
{
c[i][0]=1;
for (int j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
}
}
int main()
{
pre();
freopen("colour.in","r",stdin),freopen("colour.out","w",stdout);
T=read();
while (T--)
{
n=read(),m=read(),k=read(),s1=0,s2=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
col[i][j]=(i&1)^(j&1),s1+=col[i][j],s2+=1^col[i][j];
ans=0;
for (int i=1;i<=k;i++)
for (int j=0;j<=i;j++)
(ans+=1ll*c[k][i]*c[i][j]%P*f[s1][j]%P*f[s2][i-j]%P*fact[j]%P*fact[i-j]%P)%=P;
printf("%d\n",ans);
}
fclose(stdin),fclose(stdout);
return 0;
}