Description
Samwell Tarly is learning to draw a magical matrix to protect himself from the White Walkers.
the magical matrix is a matrix with n rows and m columns, and every single block should be painted either black or white.
Sam wants to know how many ways to paint the matrix, satisfied that the final matrix has at least A rows, B columns was painted completely black. Cause the answer might be too big, you only need to output it modulo 998244353.
Input
There might be multiple test cases, no more than 5. You need to read till the end of input.
For each test case, a line containing four integers n,m,A,B.
1≤n,m,A,B≤3000.
Output
For each test case, output a line containing the answer modulo 998244353.
Sample Input
3 4 1 2
Sample Output
169
Source
2018 Multi-University Training Contest 2
以前没有做过广义容斥的题目,今天算是学习了
有看到一篇栋爷的不错的文章,戳这
回到这题,我们先把列丢掉,记
Ans(a)
A
n
s
(
a
)
表示至少有a行全黑的方案数,那么考虑容斥,有以下式子
这里的 fa,i f a , i 是 Ans(a) A n s ( a ) 所对应的一个未知的容斥系数
我们考虑怎么求 f f
我们考虑任意一个选了行且这 i i 行全黑的方案,看看在上面的式子里它被计算了多少次
可以容易的算出次数,又因为每个方案最后应该只被算一次,所以可以列出等式
我们尝试推导 fa,i f a , i 的递推式
所以
这样我们可以在 O(n2) O ( n 2 ) 的时间内递推出容斥系数
我们发现列的问题和行的问题是等价的,所以相同的容斥系数的推法可以直接套用上去
我们考虑 Ans(a,b) A n s ( a , b ) 表示至少a行和b列全黑的方案数,则有
最后括号里的这个东西显然等于 2(n−i)(m−j) 2 ( n − i ) ( m − j ) ,于是就做完了
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define LB long double
#define ull unsigned long long
#define x first
#define y second
#define pb push_back
#define pf push_front
#define mp make_pair
#define Pair pair<int,int>
#define pLL pair<LL,LL>
#define pii pair<double,double>
const int INF=2e9;
const LL LINF=2e16;
const int magic=348;
const int MOD=998244353;
const double eps=1e-10;
const double pi=acos(-1);
inline int getint()
{
bool f;char ch;int res;
while (!isdigit(ch=getchar()) && ch!='-') {}
if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
while (isdigit(ch=getchar())) res=res*10+ch-'0';
return f?res:-res;
}
const int MAXN=3000;
inline int add(int x) {if (x>=MOD) x-=MOD;return x;}
inline int sub(int x) {if (x<0) x+=MOD;return x;}
int c[MAXN+48][MAXN+48];
inline void init_c()
{
int i,j;c[0][0]=1;
for (i=1;i<=MAXN;i++)
{
c[i][0]=c[i][i]=1;
for (j=1;j<=i-1;j++)
c[i][j]=add(c[i-1][j-1]+c[i-1][j]);
}
}
int pw[MAXN*MAXN+48];
inline void init_pw()
{
pw[0]=1;
for (register int i=1;i<=MAXN*MAXN;i++) pw[i]=add(pw[i-1]+pw[i-1]);
}
int n,m,A,B;
int fa[MAXN+48],fb[MAXN+48];
inline void init_f()
{
int i,j;
fa[A]=1;
for (i=A+1;i<=n;i++)
{
fa[i]=0;
for (j=A;j<=i-1;j++)
fa[i]=sub(fa[i]-(1ll*c[i-1][j-1]*fa[j])%MOD);
}
fb[B]=1;
for (i=B+1;i<=m;i++)
{
fb[i]=0;
for (j=B;j<=i-1;j++)
fb[i]=sub(fb[i]-(1ll*c[i-1][j-1]*fb[j])%MOD);
}
}
int main ()
{
init_c();init_pw();int i,j;
while (scanf("%d%d%d%d",&n,&m,&A,&B)!=EOF)
{
init_f();int ans=0;
for (i=A;i<=n;i++)
for (j=B;j<=m;j++)
ans=add(ans+((((1ll*fa[i]*fb[j])%MOD*c[n][i])%MOD*c[m][j])%MOD*pw[(n-i)*(m-j)])%MOD);
printf("%d\n",ans);
}
return 0;
}