[JSOI2015]染色问题

做题日期:2020.11.03

有一个N×M(N,M400)的矩阵,有C(C400)种颜色,现在要把这C种颜色全部涂在矩阵的格子中,要求每一行、每一列都至少得有一格被染色,每一种颜色都至少得涂一格。问有多少种涂色方案。

2 2 3

60


容斥原理

题目中含有多种限制条件,考虑容斥原理。首先枚举一共最多有i种颜色涂在了矩阵中,设其答案为f[i],则最终答案ans为:

ans=i=1c(1)ci(Ci)f[i]

对于每一个f[i],可以考虑二次容斥,枚举有j列涂颜色。其中(i+1)j1即为i+1种颜色(可以不涂)涂到j列的方案数(最后减去全不涂颜色的方案)。即:

f[i]=j=1m(1)m(mj)k=1n((i+1)j1)

最后预处理组合数,使用快速幂就可以在O(mclogn)的复杂度内求出答案。

#include<cstdio>
#include<iomanip>
using namespace std;
typedef long long ll;
const int N=4e2+50;
const ll MOD=1000000007;
ll f[N];
ll C[N][N];//组合数
int n,m,c;
inline void Calc()//预处理组合数
{
for(int i=0;i<=400;i++) C[i][0]=1;
for(int i=1;i<=400;i++){
for(int j=1;j<=i;j++){
C[i][j]=C[i-1][j-1]+C[i-1][j];
C[i][j]%=MOD;
}
}
}
inline ll Fast_Pow(ll a,ll b,ll p)//快速幂
{
ll ans=1,base=a;
while(b>0){
if(b&1){
ans*=base;
ans%=p;
}
base*=base;
base%=p;
b>>=1;
}
return ans;
}
inline ll Work(int x)//二次容斥求f[x]
{
ll k=1;
ll res=0;
ll tmp=1;
for(int j=1;j<=m;j++){
if((m-j)%2==0) k=1;
else k=-1;
tmp*=(ll)x+1;
tmp%=MOD;
res+=k*C[m][j]*Fast_Pow((tmp-1+MOD)%MOD,(ll)n,MOD);
res=(res+MOD)%MOD;
}
return res;
}
int main()
{
scanf("%d%d%d",&n,&m,&c);
Calc();
ll k=1;
ll ans=0;
for(int i=1;i<=c;i++){
if((c-i)%2==0) k=1;//判断当前方案是容是斥
else k=-1;
ans+=k*C[c][i]*Work(i);
ans=(ans+MOD)%MOD;//ans可能为负数,应当加MOD后%MOD
}
printf("%lld\n",ans);
return 0;
}

本文作者:lxzy

本文链接:https://www.cnblogs.com/Unlimited-Chan/p/14026662.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   lxzy  阅读(189)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.