『容斥原理·组合计数』暗箱

P r o b l e m \mathrm{Problem} Problem

在这里插入图片描述


S o l u t i o n \mathrm{Solution} Solution

这里有横向和纵向两种条件,我们可以优先满足纵向再满足横向。

那么只考虑纵向满足的话,方案数为: ( 2 n − 1 ) m (2^n-1)^m (2n1)m

我们可以定义这样的方案数为全集,我们要在全集中找到所有满足横向条件的方案数。

  • 若只有一行不满足条件,则答案为: n × ( 2 n − 1 − 1 ) m n\times (2^{n-1}-1)^m n×(2n11)m
  • 若存在两行不满足条件,则答案为: C n 2 × 2 n − 2 − 1 m C_{n}^{2} \times \mathrm{2^{n-2}-1}^m Cn2×2n21m
  • 以此类推。

这样我们就得到了答案的表达式: ( 2 n − 1 ) m + ∑ i = 1 n ( − 1 ) n C n i ( 2 n − i − 1 ) m (2^n-1)^m+\sum_{i=1}^{n}(-1)^nC_{n}^{i}(2^{n-i}-1)^m (2n1)m+i=1n(1)nCni(2ni1)m


S o l u t i o n \mathrm{Solution} Solution

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 2e6;
const int P = 998244353;

int A, B, n, m, res(0);
int fac[N];
char a[N], b[N];

int power(int a, int b)
{
	int res = 1;
	while (b > 0) {
		if (b % 2 == 1) res = 1LL * res * a % P;
		a = 1LL * a * a % P, b >>= 1;
	}
	return res;
}

int C(int n, int m) {
	int A = fac[n];
	int B = 1LL * fac[m] * fac[n - m] % P;
	return A * power(B, P-2) % P; 
}

void work(int n, int m)
{
	fac[0] = 1;
	for (int i=1;i<=1e6;++i) fac[i] = 1LL * fac[i-1] * i % P;
	res = power(power(2, n) - 1, m);
	for (int i=1;i<=n;++i) {
		int opt = i % 2 ? -1 : 1;
		int val = 1LL * power(power(2, n-i) - 1, m) * C(n, i) % P;
		res += opt * val, res %= P;
	}
	res = (res % P + P) % P;
	cout << res << endl;
	return;
}

signed main(void)
{
	freopen("box.in","r",stdin);
	freopen("box.out","w",stdout); 
	cin >> A >> B >> a + 1 >> b + 1;
	n = A, m = B;
	for (int i=1;i<=A;++i) n -= (a[i] == '.');
	for (int i=1;i<=B;++i) m -= (b[i] == '.');
	work(n, m);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值