abc242 F - Black and White Rooks

放置事实上等同于 2 种颜色所覆盖到的行、列集合没交。

考虑枚举 2 种颜色各自放置的行列。

i,jf[i][j]g[i][j](ni+x)(i+xi)(mj+y)(j+yj)

f[i][j] 为选择的黑色点仅包含 ij 列的方案数。

考虑仅包含,那么显然选择的是 ij 列交的矩形,即 f[i][j]=(ijB)

考虑对于一个小的方案可能会在大的方案贡献到,那么我们所选择的必须没有一行、一列是空的。这个的话发现是恰好,可以类似于 这道题,直接用二项式反演。
或者使用递推,减去实际占的行列不够的。

二项式反演

#include <bits/stdc++.h> #define int long long #define pb push_back using namespace std; #define N 2502 const int mod=998244353; int fpow(int x,int y) { int res=1; while(y) { if(y&1) res=res*x%mod; y>>=1; x=x*x%mod; } return res; } int f[52][52],g[52][52],a[52][52],b[52][52],jie[N],djie[N],n,m,B,W; int C(int n,int m) { if(m>n||n<=0||m<0) return 0; return jie[n]*djie[m]%mod*djie[n-m]%mod; } signed main() { cin.tie(0); ios::sync_with_stdio(false); jie[0]=djie[0]=1; for(int i=1;i<=2500;i++) jie[i]=jie[i-1]*i%mod,djie[i]=fpow(jie[i],mod-2); cin>>n>>m>>B>>W; for(int x=1;x<=n;x++) { for(int y=1;y<=m;y++) { for(int i=0;i<=x;i++) { for(int j=0;j<=y;j++) { a[i][j]=C(x,i)*C(y,j)%mod*C(x*y-(i*y+j*x-i*j),B)%mod; } } int qwq=0; for(int i=0;i<=x;i++) { for(int j=0;j<=y;j++) { qwq=(qwq+(((i+j)&1)?-1:1)*a[i][j]%mod)%mod; } } f[x][y]=qwq; // cout<<qwq<<' '; } // cout<<'\n'; } for(int x=1;x<=n;x++) { for(int y=1;y<=m;y++) { for(int i=0;i<=x;i++) { for(int j=0;j<=y;j++) { a[i][j]=C(x,i)*C(y,j)%mod*C(x*y-(i*y+j*x-i*j),W)%mod; } } int qwq=0; for(int i=0;i<=x;i++) { for(int j=0;j<=y;j++) { qwq=(qwq+(((i+j)&1)?-1:1)*a[i][j]%mod)%mod; } } g[x][y]=qwq; // cout<<qwq<<' '; } // cout<<'\n'; } int ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { for(int x=1;x<=n;x++) { for(int y=1;y<=m;y++) { ans=(ans+f[i][j]*g[x][y]%mod*C(n,i+x)%mod*C(i+x,i)%mod*C(m,j+y)%mod*C(j+y,j)%mod)%mod; } } } } ans=(ans%mod+mod)%mod; cout<<ans; return 0; }

递推

#include <bits/stdc++.h> #define int long long #define pb push_back using namespace std; #define N 2502 const int mod=998244353; int fpow(int x,int y) { int res=1; while(y) { if(y&1) res=res*x%mod; y>>=1; x=x*x%mod; } return res; } int f[52][52],g[52][52],jie[N],djie[N],n,m,b,w; int C(int n,int m) { if(m>n||n<=0||m<0) return 0; return jie[n]*djie[m]%mod*djie[n-m]%mod; } signed main() { cin.tie(0); ios::sync_with_stdio(false); jie[0]=djie[0]=1; for(int i=1;i<=2500;i++) jie[i]=jie[i-1]*i%mod,djie[i]=fpow(jie[i],mod-2); cin>>n>>m>>b>>w; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { f[i][j]=C(i*j,b); // if(!f[i][j]) continue ; for(int x=1;x<=i;x++) { for(int y=1;y<=j;y++) { if(x==i&&y==j) continue ; f[i][j]=(f[i][j]-f[x][y]*C(i,x)%mod*C(j,y)%mod)%mod; } } // if(f[i][j]<0) f[i][j]=0; // cout<<f[i][j]<<" "; } // cout<<'\n'; } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { g[i][j]=C(i*j,w); // if(!g[i][j]) continue ; for(int x=1;x<=i;x++) { for(int y=1;y<=j;y++) { if(x==i&&y==j) continue ; g[i][j]=(g[i][j]-g[x][y]*C(i,x)%mod*C(j,y)%mod)%mod; } } // if(g[i][j]<0) g[i][j]=0; // cout<<g[i][j]<<" "; } // cout<<'\n'; } int ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { for(int x=1;x<=n;x++) { for(int y=1;y<=m;y++) { ans=(ans+f[i][j]*g[x][y]%mod*C(n,i+x)%mod*C(i+x,i)%mod*C(m,j+y)%mod*C(j+y,j)%mod)%mod; } } } } ans=(ans%mod+mod)%mod; cout<<ans; return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/15971266.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(125)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示