Matrix HDU - 6314(推式子好题)

题目大意:

\(Samwell·Tarly\) 正在学习绘制魔法矩阵,以保护自己免受白人步行者的伤害。
魔法矩阵是一个有 \(n\) 行和 \(m\) 列的矩阵,每个格子都应该涂成黑色或白色。
Sam想知道有多少种方法来绘制矩阵,满足于最终矩阵至少有 \(A\) 行和 \(B\) 列被绘制为完全黑色。因为答案可能太大,您只需要对 \(998244353\) 取模。

分析:

一道不错的推式子的好题。

首先,设 \(F[x][y]\) 为在大小为 \(x \times y\) 的矩阵中,乱涂色,但保证每一行,每一列都不完全为黑色的数量。根据容斥原理,容易得到:

\[F[x][y] = \sum_{i = 0}^x\sum_{j = 0}^y{x\choose i} * {y \choose j} * {(-1)}^{i+j} * 2^{(n - i) * (m-j)} \]

假如我们求得了 \(F[x][y]\),那么答案 \(ans\) 就能很容易地求出来,即:

\[ans=\sum_{i=A}^n\sum_{j=B}^m{n \choose i}*{m\choose j} * F[n-i][m-j] \]

然而直接求 \(F[x][y]\) 的时间复杂度为 \(O(n^2*m^2)\),无疑是无法接受的,因此考虑将 \(F\) 的表达式代入,得到:

\[ans=\sum_{i=A}^n\sum_{j=B}^m\sum_{p = 0}^{n-i}\sum_{q = 0}^{m-j}{n \choose i}*{m\choose j} * {{n-i}\choose p} * {{m-j} \choose q} * {(-1)}^{p+q} * 2^{(n - p) * (m-q)} \]

移项,得:

\[ans=\sum_{i=A}^n\sum_{j=B}^m\sum_{p = 0}^{n-i}\sum_{q = 0}^{m-j}((-1)^p * {n \choose i}*{{n-i}\choose p}) *({m\choose j} * {{m-j} \choose q} * {(-1)}^{q}) * 2^{(n - i-p) * (m-j-q)} \]

\(t1 = i + p\)\(t2 = j + q\),代入得:

\[ans=\sum_{t1=A}^n\sum_{t2=B}^m2^{(n - t1) * (m-t2)}\sum_{i = A}^{t1}\sum_{j = B}^{t2}((-1)^{t1-i} * {n \choose i}*{{n-i}\choose t1-i}) *({m\choose j} * {{m-j} \choose t2-j} * {(-1)}^{t2-j}) \]

即:

\[ans=\sum_{t1=A}^n\sum_{t2=B}^m2^{(n - t1) * (m-t2)}\sum_{i = A}^{t1}((-1)^{t1-i} * {n \choose i}*{{n-i}\choose t1-i}) *\sum_{j = B}^{t2}({m\choose j} * {{m-j} \choose t2-j} * {(-1)}^{t2-j}) \]

\(Fa[t]=\sum_{i = A}^{t}((-1)^{t-i} * {n \choose i}*{{n-i}\choose t-i})\)\(Fb[t] = \sum_{j = B}^{t}({m\choose j} * {{m-j} \choose t-j} * {(-1)}^{t-j})\)

预处理时间复杂度分别为 \(O(n^2)\)\(O(m^2)\)

则有:

\[ans=\sum_{t1=A}^n\sum_{t2=B}^m2^{(n - t1) * (m-t2)}Fa[t1] *Fb[t2] \]

Code:

#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 3e3;
const int MOD = 998244353;
int fa[MAXN + 5],fb[MAXN + 5],dp[MAXN + 5][MAXN + 5],p[30000005],n,m,a,b;
inline int qpow(int a,int m){
	int ret = 1;
	while(m){
		if(m % 2 == 1){
			ret *= a % MOD;
			ret %= MOD;
		}
		m /= 2;
		a = a * a % MOD;
	}
	return ret;
}
void pre(){
	p[0] = 1;
	for(int i = 1; i <= 3e6; i++){
		p[i] = p[i - 1] * 2;
		p[i] %= MOD;
	}
}
signed main(){
	dp[0][0] = 1;
	for(int i = 1;i <= MAXN; i++){
		for(int j = 0; j <= i; j++){
			if(j == 0 || j == i)dp[i][j] = 1;
			else dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
		}
	}
	pre();
	while(scanf("%lld%lld%lld%lld",&n,&m,&a,&b) == 4){
		memset(fa,0,sizeof fa);
		memset(fb,0,sizeof fb);
		for(int t = a; t <= n; t ++){
			for(int i = a; i <= t; i++){
				fa[t] += dp[n][i] * dp[n - i][t - i] * ((t - i) % 2 ? -1 : 1);
			}
		}
		for(int t = b; t <= m; t ++){
			for(int i = b; i <= t; i ++){
				fb[t] += dp[m][i] * dp[m - i][t - i] * ((t - i) % 2 ? -1 : 1);
			}
		}
		int ans = 0;
		for(int t1 = a; t1 <= n; t1++){
			for(int t2 = b; t2 <= m; t2++){
				ans += p[(n - t1) * (m - t2)] * (long long)(fa[t1] * fb[t2]) % MOD;
				ans %= MOD;
			}
		}
		cout << ans << "\n";
	}
} 
posted @ 2022-08-15 11:45  腾云今天首飞了吗  阅读(26)  评论(0编辑  收藏  举报