题意:
给你一个
n
∗
m
n*m
n∗m的棋盘,有
k
k
k种颜色,一开始棋盘上的每一个位置都是白色。要求你给棋盘染色,要求每行至少有一个格子被染色,每列至少有一个位置被染色,整个棋盘染完色后这
k
k
k种颜色都要出现过,求方案数。对
1
0
9
+
7
10^9+7
109+7取模。
n
,
m
,
c
<
=
400
n,m,c<=400
n,m,c<=400。
题解:
反正我是没想出这个题。可能我容斥水平还是有点差吧。
这个题上来是个三重容斥,就是你对于行、列、颜色都进行容斥。我们比较好计算的是,至多有
i
i
i行每行都至少有一个格子被染色,至多有
j
j
j列每列至多一个格子被染色,至多用了
k
k
k种颜色的方案数。于是就是一个三重容斥,算容斥系数的时候三个系数要乘一起去。式子不难列:
a
n
s
=
∑
i
=
0
n
∑
j
=
0
m
∑
k
=
0
c
(
−
1
)
n
−
i
+
m
−
j
+
c
−
k
C
n
i
∗
C
m
j
∗
C
c
k
∗
(
k
+
1
)
i
∗
j
ans=\sum_{i=0}^n\sum_{j=0}^m\sum_{k=0}^c(-1)^{n-i+m-j+c-k}C_{n}^i*C_m^j*C_c^k*(k+1)^{i*j}
ans=i=0∑nj=0∑mk=0∑c(−1)n−i+m−j+c−kCni∗Cmj∗Cck∗(k+1)i∗j
这样就可以
O
(
n
3
)
O(n^3)
O(n3)算出答案,是可以通过这个题的,但是我们还有更优秀的做法。
我们化一下式子:
∑
i
=
0
n
∑
j
=
0
m
∑
k
=
0
c
(
−
1
)
n
−
i
+
m
−
j
+
c
−
k
C
n
i
∗
C
m
j
∗
C
c
k
∗
(
k
+
1
)
i
∗
j
\sum_{i=0}^n\sum_{j=0}^m\sum_{k=0}^c(-1)^{n-i+m-j+c-k}C_{n}^i*C_m^j*C_c^k*(k+1)^{i*j}
i=0∑nj=0∑mk=0∑c(−1)n−i+m−j+c−kCni∗Cmj∗Cck∗(k+1)i∗j
=
∑
i
=
0
n
∑
k
=
0
c
(
−
1
)
n
−
i
+
m
+
c
−
k
C
n
i
∗
C
c
k
∗
∑
j
=
0
m
C
m
j
∗
(
−
1
)
j
∗
(
k
+
1
)
i
∗
j
=\sum_{i=0}^n\sum_{k=0}^c(-1)^{n-i+m+c-k}C_{n}^i*C_c^k*\sum_{j=0}^mC_m^j*(-1)^j*(k+1)^{i*j}
=i=0∑nk=0∑c(−1)n−i+m+c−kCni∗Cck∗j=0∑mCmj∗(−1)j∗(k+1)i∗j 我们发现后面可以看作一个二项式展开式,于是进行化简
=
∑
i
=
0
n
∑
k
=
0
c
(
−
1
)
n
−
i
+
m
+
c
−
k
C
n
i
∗
C
c
k
∗
(
1
−
(
k
+
1
)
i
)
m
=\sum_{i=0}^n\sum_{k=0}^c(-1)^{n-i+m+c-k}C_{n}^i*C_c^k*(1-(k+1)^i)^m
=i=0∑nk=0∑c(−1)n−i+m+c−kCni∗Cck∗(1−(k+1)i)m
前面的组合数预处理出来,后面部分每次用快速幂计算,复杂度是
O
(
n
∗
c
∗
l
o
g
m
)
O(n*c*logm)
O(n∗c∗logm)的。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,c;
const long long mod=1e9+7;
long long ans,jie[410],ni[410];
inline long long ksm(long long x,long long y)
{
long long res=1;
while(y)
{
if(y&1)
res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
int main()
{
scanf("%d%d%d",&n,&m,&c);
jie[0]=1;
for(int i=1;i<=400;++i)
jie[i]=jie[i-1]*i%mod;
ni[400]=ksm(jie[400],mod-2);
for(int i=399;i>=0;--i)
ni[i]=ni[i+1]*(i+1)%mod;
for(int i=0;i<=n;++i)
{
for(int k=0;k<=c;++k)
{
int opt=1;
if((n+m+c-i-k)&1)
opt=-1;
ans=(ans+opt*jie[n]*ni[i]%mod*ni[n-i]%mod*jie[c]%mod*ni[k]%mod*ni[c-k]%mod*ksm((1-ksm(k+1,i)+mod)%mod,m)%mod+mod)%mod;
}
}
printf("%lld\n",ans);
return 0;
}