【HDU - 6314】Matrix

@Matrix@


@题目描述 - English@

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

@大致题意@

一个n*m的矩阵被黑白两色填充,每个格子要么是黑色要么是白色。问最后至少有A行B列是全黑的方案数。

@分析1:答案表达式@

考虑这样一种计数方式:统计恰有 i 行 j 列是全黑的方案数的和(A<=i<=n, B<=j<=m)。选择这 i 行 j 列的方案数可以用组合数计算。那么可以发现,删除了这 i 行 j 列剩下的矩阵任意一行或一列都不是全黑的。我们记 f[n][m] 为n*m的矩阵任意一行或一列都不是全黑的方案数,则:

ans=i=Anj=BmC(n,i)C(m,j)f[ni][mj] a n s = ∑ i = A n ∑ j = B m C ( n , i ) ∗ C ( m , j ) ∗ f [ n − i ] [ m − j ]

考虑 f[n][m] 应该怎么进行计算,我们可以使用容斥原理。用总方案数减去至少一行是全黑的方案数,再加上多减掉至少两行是全黑的方案数,再减去多加上的至少三行是全黑的方案数……因为 f 是二维的,所以我们不仅要考虑行还有列,即还要减去至少一列是全黑的方案数,加上多减掉的至少一行一列是全黑的方案数,减去……
怎么计算至少 i 行 j 列是全黑的方案数呢?我们先要选出这 i 行 j 列,这里的方案数可以用组合数得到。则这 i 行 j 列的颜色固定,其他格子的颜色有两种情况任意挑选。即2的 其他格子数 次幂。
则可以得到 f[n][m] 的表达式为:

f[n][m]=p=0nq=0m(1)p+qC(n,p)C(m,q)2(np)(mq) f [ n ] [ m ] = ∑ p = 0 n ∑ q = 0 m ( − 1 ) p + q ∗ C ( n , p ) ∗ C ( m , q ) ∗ 2 ( n − p ) ∗ ( m − q )

但是……很悲伤的是 f 共有O(n^2)个元素,每个元素需要O(n^2)的计算……这样的话时间复杂度急速退化到O(n^4)。

@分析2:表达式快速求解@

将 f[n][m] 的表达式代入 ans 的表达式中,得:

ans=i=Anj=BmC(n,i)C(m,j)(p=0niq=0mj(1)p+qC(ni,p)C(mj,q)2(nip)(mjq)) a n s = ∑ i = A n ∑ j = B m C ( n , i ) ∗ C ( m , j ) ∗ ( ∑ p = 0 n − i ∑ q = 0 m − j ( − 1 ) p + q ∗ C ( n − i , p ) ∗ C ( m − j , q ) ∗ 2 ( n − i − p ) ∗ ( m − j − q ) )

将累加提前,得:

ans=i=Anj=Bmp=0niq=0mjC(n,i)C(m,j)(1)p+qC(ni,p)C(mj,q)2(nip)(mjq) a n s = ∑ i = A n ∑ j = B m ∑ p = 0 n − i ∑ q = 0 m − j C ( n , i ) ∗ C ( m , j ) ∗ ( − 1 ) p + q ∗ C ( n − i , p ) ∗ C ( m − j , q ) ∗ 2 ( n − i − p ) ∗ ( m − j − q )

将组合数拆成阶乘形式,得:

ans=i=Anj=Bmp=0niq=0mjn!i!(ni)!m!j!(mj)!(1)p+q(ni)!p!(nip)!(mj)!q!(mjq)!2(nip)(mjq) a n s = ∑ i = A n ∑ j = B m ∑ p = 0 n − i ∑ q = 0 m − j n ! i ! ∗ ( n − i ) ! ∗ m ! j ! ∗ ( m − j ) ! ∗ ( − 1 ) p + q ∗ ( n − i ) ! p ! ∗ ( n − i − p ) ! ∗ ( m − j ) ! q ! ∗ ( m − j − q ) ! ∗ 2 ( n − i − p ) ∗ ( m − j − q )

整理得:

ans=i=Anj=Bmp=0niq=0mjn!m!(1)p+q2(nip)(mjq)(ni)!(mj)!i!(ni)!j!(mj)!p!(nip)!q!(mjq)! a n s = ∑ i = A n ∑ j = B m ∑ p = 0 n − i ∑ q = 0 m − j n ! ∗ m ! ∗ ( − 1 ) p + q ∗ 2 ( n − i − p ) ∗ ( m − j − q ) ∗ ( n − i ) ! ∗ ( m − j ) ! i ! ∗ ( n − i ) ! ∗ j ! ∗ ( m − j ) ! ∗ p ! ∗ ( n − i − p ) ! ∗ q ! ∗ ( m − j − q ) !

【这个时候可以发现一些异样了……上面有着 2(nip)(mjq) 2 ( n − i − p ) ∗ ( m − j − q ) 这诡异的一项,下面也有个 (nip)!(mjq)! ( n − i − p ) ! ∗ ( m − j − q ) ! 这么相似的一项……于是下面的分类我们就以这个为关键点】
n!m! n ! ∗ m ! 提出来,将 (ni)! ( n − i ) ! (mj)! ( m − j ) ! 上下约分,并再次整理分类得:

ans=n!m!i=Anj=Bmp=0niq=0mj2nip(nip)!(1)pi!p!2mjq(mjq)!(1)qj!q! a n s = n ! ∗ m ! ∗ ∑ i = A n ∑ j = B m ∑ p = 0 n − i ∑ q = 0 m − j 2 n − i − p ( n − i − p ) ! ∗ ( − 1 ) p i ! ∗ p ! ∗ 2 m − j − q ( m − j − q ) ! ∗ ( − 1 ) q j ! ∗ q !

OK,我们所需要的式子变形就可以到此为止了。依次记四个相乘起来的部分为fA, fB, fC, fD。
即令 ans=n!m!ni=Amj=Bnip=0mjq=0fAfBfCfD a n s = n ! ∗ m ! ∗ ∑ i = A n ∑ j = B m ∑ p = 0 n − i ∑ q = 0 m − j f A ∗ f B ∗ f C ∗ f D

观察发现当i+p为定值时,fA部分也始终为定值。对于fC也同理。我们令 F[k][l] 表示n-i-p=k, m-j-q=l时fA*fC的值,F可以用O(n^2)的时间复杂度求解。则接下来只需要考虑fB与fD的问题了。因为它们两个形式相似,我们现在只考虑fB。注意到i有取值范围的限制,所以我们令G[k][l]表示i>=l且i+p=k时fB的值。G[k][l]可以由G[k][l+1]递推而来,所以也可以做到O(n^2)的时间复杂度预处理出来。观察i与p的取值,可以发现i+p最大不会超过n。
因此,最终答案为:

ans=k=Anl=BmF[nk][ml]G[k][A]G[l][B] a n s = ∑ k = A n ∑ l = B m F [ n − k ] [ m − l ] ∗ G [ k ] [ A ] ∗ G [ l ] [ B ]

因为F与G已经预处理好了,所以最终求解的复杂度仍不超过O(n^2)。

@代码@

【当时……万恶的“Hack it”不知毒害了我们这个队多长时间】
【所以这道题……看都没有看到嘤嘤嘤】
如果还有什么疑问或不懂的地方可以参考代码细节或留言问我……我也不知道能不能帮忙解答因为这道题就是一个纯粹的推式子题目qwq

#include<cstdio>
typedef long long ll;
const int MAXN = 3000;
const int MOD = 998244353;
int fact[MAXN + 5], inv[MAXN + 5], pw2[MAXN*MAXN + 5];
int PowMod(int b, int k) {
    int ret = 1;
    while( k ) {
        if( k & 1 ) ret = 1LL * ret * b % MOD;
        b = 1LL * b * b % MOD;
        k >>= 1;
    }
    return ret;
}
int F[MAXN + 5][MAXN + 5], G[MAXN + 5][MAXN + 5];
void init() {
    fact[0] = 1;
    for(int i=1;i<=MAXN;i++)
        fact[i] = 1LL * fact[i-1] * i % MOD;
    inv[MAXN] = PowMod(fact[MAXN], MOD-2);
    for(int i=MAXN-1;i>=0;i--)
        inv[i] = 1LL * inv[i+1] * (i+1) % MOD;
    pw2[0] = 1;
    for(int i=1;i<=MAXN*MAXN;i++)
        pw2[i] = 1LL * pw2[i-1] * 2 % MOD;
    for(int i=0;i<=MAXN;i++)
        for(int j=0;j<=MAXN;j++)
            F[i][j] = 1LL * pw2[i*j] * inv[i] % MOD * inv[j] % MOD;
    for(int i=0;i<=MAXN;i++) {
        G[i][i] = 1LL * inv[i] * inv[0] % MOD * PowMod(-1, 0);
        for(int j=i-1;j>=0;j--)
            G[i][j] = (G[i][j+1] + 1LL * inv[j] * inv[i-j] % MOD * PowMod(-1, (i-j)&1) + MOD) % MOD;
    }
}
int main() {
    init();
    int n, m, A, B;
    while( scanf("%d%d%d%d", &n, &m, &A, &B) == 4 ) {
        int ans = 0;
        for(int k=A;k<=n;k++)
            for(int l=B;l<=m;l++)
                ans = (ans + 1LL*F[n-k][m-l]*G[k][A]%MOD*G[l][B]%MOD) % MOD;
        printf("%d\n", int(1LL * ans * fact[n] % MOD * fact[m] % MOD) );
    }
}

【吐槽:好像网上一大群人抱怨卡常……但是我这个的确是一次过的啊2333】

@END OF ALL@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值