版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/88915790
题意:
给你一个
的棋盘,有
种颜色,一开始棋盘上的每一个位置都是白色。要求你给棋盘染色,要求每行至少有一个格子被染色,每列至少有一个位置被染色,整个棋盘染完色后这
种颜色都要出现过,求方案数。对
取模。
。
题解:
反正我是没想出这个题。可能我容斥水平还是有点差吧。
这个题上来是个三重容斥,就是你对于行、列、颜色都进行容斥。我们比较好计算的是,至多有
行每行都至少有一个格子被染色,至多有
列每列至多一个格子被染色,至多用了
种颜色的方案数。于是就是一个三重容斥,算容斥系数的时候三个系数要乘一起去。式子不难列:
这样就可以
算出答案,是可以通过这个题的,但是我们还有更优秀的做法。
我们化一下式子:
我们发现后面可以看作一个二项式展开式,于是进行化简
前面的组合数预处理出来,后面部分每次用快速幂计算,复杂度是
的。
代码:
#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;
}