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 (2n−1)m
我们可以定义这样的方案数为全集,我们要在全集中找到所有满足横向条件的方案数。
- 若只有一行不满足条件,则答案为: n × ( 2 n − 1 − 1 ) m n\times (2^{n-1}-1)^m n×(2n−1−1)m
- 若存在两行不满足条件,则答案为: C n 2 × 2 n − 2 − 1 m C_{n}^{2} \times \mathrm{2^{n-2}-1}^m Cn2×2n−2−1m
- 以此类推。
这样我们就得到了答案的表达式: ( 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 (2n−1)m+i=1∑n(−1)nCni(2n−i−1)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;
}