Problem p03595 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fi first
#define se second
#define mp make_pair
#define pb push_back

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef long double ld;
typedef tree<ii, null_type, less<ii>, rb_tree_tag,
             tree_order_statistics_node_update>
    pbds;
vector<int> fact;
vector<int> ifact;
vector<int> inv;
vector<int> pow2;
vector<int> ipow2;
const int MOD = 998244353;
int add(int a, int b) {
  a += b;
  while (a >= MOD)
    a -= MOD;
  return a;
}
int mult(int a, int b) { return (a * 1LL * b) % MOD; }
int modpow(int a, int b) {
  int r = 1;
  while (b) {
    if (b & 1)
      r = mult(r, a);
    a = mult(a, a);
    b >>= 1;
  }
  return r;
}
int choose(int a, int b) {
  if (b == 0)
    return 1;
  if (a < b)
    return 0;
  if (a == b)
    return 1;
  return mult(fact[a], mult(ifact[b], ifact[a - b]));
}
int inverse(int a) { return modpow(a, MOD - 2); }
void init(int _n) {
  fact.clear();
  ifact.clear();
  inv.clear();
  pow2.clear();
  ipow2.clear();
  fact.resize(_n + 1);
  ifact.resize(_n + 1);
  inv.resize(_n + 1);
  pow2.resize(_n + 1);
  ipow2.resize(_n + 1);
  pow2[0] = ipow2[0] = 1;
  ifact[0] = 1;
  fact[0] = 1;
  for (int i = 1; i <= _n; i++) {
    pow2[i] = add(pow2[i - 1], pow2[i - 1]);
    fact[i] = mult(fact[i - 1], i);
    ipow2[i] = inverse(pow2[i]);
    // ifact[i]=mult(ifact[i-1],inv[i]);
  }
  ifact[_n] = inverse(fact[_n]);
  for (int i = _n - 1; i >= 1; i--) {
    ifact[i] = mult(ifact[i + 1], i + 1);
  }
  for (int i = 1; i <= _n; i++) {
    inv[i] = mult(fact[i - 1], ifact[i]);
  }
}

int l[111111];
int r[111111];
int u[111111];
int d[111111];
int prefL[111111];
int prefR[111111];
int prefU[111111];
int prefD[111111];
int prefUD[111111];

int sumL(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefL[r];
  else
    return add(prefL[r], MOD - prefL[l - 1]);
}

int sumR(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefR[r];
  else
    return add(prefR[r], MOD - prefR[l - 1]);
}

int sumU(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefU[r];
  else
    return add(prefU[r], MOD - prefU[l - 1]);
}

int sumD(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefD[r];
  else
    return add(prefD[r], MOD - prefD[l - 1]);
}

int sumUD(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefUD[r];
  else
    return add(prefUD[r], MOD - prefUD[l - 1]);
}

int solve(int r, int c) { return choose(r + c - 1, r); }

void calcL(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefL[i] = (s[i] == '1');
    if (i > 0)
      prefL[i] += prefL[i - 1];
  }
}

void calcR(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefR[i] = (s[i] == '1');
    if (i > 0)
      prefR[i] += prefR[i - 1];
  }
}

void calcU(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefU[i] = (s[i] == '1');
    if (i > 0)
      prefU[i] += prefU[i - 1];
  }
}

void calcD(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefD[i] = (s[i] == '1');
    if (i > 0)
      prefD[i] += prefD[i - 1];
  }
}

void calcUD(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefUD[i] = (s[i] == '1');
    if (i > 0)
      prefUD[i] += prefUD[i - 1];
  }
}

int dpl[222222];
int dpr[222222];

int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  init(233333);
  int n, m;
  cin >> n >> m;
  string L, R, U, D;
  cin >> L;
  cin >> R;
  cin >> U;
  cin >> D;
  string sud;
  for (int i = 0; i < U.length(); i++)
    sud += char('0' + ((U[i] - '0') & (D[i] - '0')));
  calcL(L);
  calcR(R);
  calcU(U);
  calcD(D);
  calcUD(sud);
  if (sumL(0, n - 1) == 0 && sumR(0, n - 1) == 0 && sumU(0, m - 1) == 0 &&
      sumD(0, m - 1) == 0) {
    cout << 1 << '\n';
    return 0;
  }
  for (int l = 0; l < m; l++) {
    int ltot = sumL(0, n - 1);
    int c1 = sumU(0, l - 1);
    int c2 = sumD(0, l - 1);
    if (l == 0)
      dpl[l] = 1;
    else
      dpl[l] = choose(c1 + c2 - 1 + ltot, c1 + c2);
  }
  for (int r = 0; r < m; r++) {
    int ltot = sumR(0, n - 1);
    int c1 = sumU(r + 1, m - 1);
    int c2 = sumD(r + 1, m - 1);
    if (r == m - 1)
      dpr[r] = 1;
    else
      dpr[r] = choose(c1 + c2 - 1 + ltot, c1 + c2);
  }
  int ans = 0;
  for (int l = 0; l < m; l++) {
    int r = l;
    int coeff = mult(pow2[sumUD(l + 1, r - 1)],
                     ((U[l] == '1') + (D[l] == '1')) *
                         (l == r ? 1 : ((U[r] == '1') + (D[r] == '1'))));
    if (coeff == 0)
      continue;
    int res1 = dpl[l];
    int res2 = dpr[r];
    ans = add(ans, mult(coeff, mult(res1, res2)));
  }
  for (int l = 0; l < m; l++) {
    dpl[l] = mult(dpl[l], ipow2[prefUD[l]]);
    dpl[l] = mult(dpl[l], (U[l] == '1') + (D[l] == '1'));
  }
  for (int r = 0; r < m; r++) {
    dpr[r] = mult(dpr[r], pow2[(r > 0 ? prefUD[r - 1] : 0)]);
    dpr[r] = mult(dpr[r], (U[r] == '1') + (D[r] == '1'));
  }
  int sum = 0;
  for (int l = 0; l + 1 < m; l++) {
    // solve for all r>l
    sum = add(sum, dpl[l]);
    ans = add(ans, mult(sum, dpr[l + 1]));
  }
  swap(U, L);
  swap(R, D);
  swap(n, m);
  sud = "";
  for (int i = 0; i < U.length(); i++)
    sud += char('0' + ((U[i] - '0') & (D[i] - '0')));
  calcL(L);
  calcR(R);
  calcU(U);
  calcD(D);
  calcUD(sud);
  for (int l = 0; l < m; l++) {
    int ltot = sumL(0, n - 1);
    int c1 = sumU(0, l - 1);
    int c2 = sumD(0, l - 1);
    if (l == 0)
      dpl[l] = 1;
    else
      dpl[l] = choose(c1 + c2 - 1 + ltot, c1 + c2);
  }
  for (int r = 0; r < m; r++) {
    int ltot = sumR(0, n - 1);
    int c1 = sumU(r + 1, m - 1);
    int c2 = sumD(r + 1, m - 1);
    if (r == m - 1)
      dpr[r] = 1;
    else
      dpr[r] = choose(c1 + c2 - 1 + ltot, c1 + c2);
  }
  for (int l = 0; l < m; l++) {
    int r = l;
    int coeff = mult(pow2[sumUD(l + 1, r - 1)],
                     ((U[l] == '1') + (D[l] == '1')) *
                         (l == r ? 1 : ((U[r] == '1') + (D[r] == '1'))));
    if (coeff == 0)
      continue;
    int res1 = dpl[l];
    int res2 = dpr[r];
    ans = add(ans, mult(coeff, mult(res1, res2)));
  }
  for (int l = 0; l < m; l++) {
    dpl[l] = mult(dpl[l], ipow2[prefUD[l]]);
    dpl[l] = mult(dpl[l], (U[l] == '1') + (D[l] == '1'));
  }
  for (int r = 0; r < m; r++) {
    dpr[r] = mult(dpr[r], pow2[(r > 0 ? prefUD[r - 1] : 0)]);
    dpr[r] = mult(dpr[r], (U[r] == '1') + (D[r] == '1'));
  }
  sum = 0;
  for (int l = 0; l + 1 < m; l++) {
    // solve for all r>l
    sum = add(sum, dpl[l]);
    ans = add(ans, mult(sum, dpr[l + 1]));
  }
  cout << ans << '\n';
}


Fixed submission:
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

#define fi first
#define se second
#define mp make_pair
#define pb push_back

typedef long long ll;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef long double ld;
typedef tree<ii, null_type, less<ii>, rb_tree_tag,
             tree_order_statistics_node_update>
    pbds;
vector<int> fact;
vector<int> ifact;
vector<int> inv;
vector<int> pow2;
vector<int> ipow2;
const int MOD = 998244353;
int add(int a, int b) {
  a += b;
  while (a >= MOD)
    a -= MOD;
  return a;
}
int mult(int a, int b) { return (a * 1LL * b) % MOD; }
int modpow(int a, int b) {
  int r = 1;
  while (b) {
    if (b & 1)
      r = mult(r, a);
    a = mult(a, a);
    b >>= 1;
  }
  return r;
}
int choose(int a, int b) {
  if (b == 0)
    return 1;
  if (a < b)
    return 0;
  if (a == b)
    return 1;
  return mult(fact[a], mult(ifact[b], ifact[a - b]));
}
int inverse(int a) { return modpow(a, MOD - 2); }
void init(int _n) {
  fact.clear();
  ifact.clear();
  inv.clear();
  pow2.clear();
  ipow2.clear();
  fact.resize(_n + 1);
  ifact.resize(_n + 1);
  inv.resize(_n + 1);
  pow2.resize(_n + 1);
  ipow2.resize(_n + 1);
  pow2[0] = ipow2[0] = 1;
  ifact[0] = 1;
  fact[0] = 1;
  for (int i = 1; i <= _n; i++) {
    pow2[i] = add(pow2[i - 1], pow2[i - 1]);
    fact[i] = mult(fact[i - 1], i);
    ipow2[i] = inverse(pow2[i]);
    // ifact[i]=mult(ifact[i-1],inv[i]);
  }
  ifact[_n] = inverse(fact[_n]);
  for (int i = _n - 1; i >= 1; i--) {
    ifact[i] = mult(ifact[i + 1], i + 1);
  }
  for (int i = 1; i <= _n; i++) {
    inv[i] = mult(fact[i - 1], ifact[i]);
  }
}

int l[111111];
int r[111111];
int u[111111];
int d[111111];
int prefL[111111];
int prefR[111111];
int prefU[111111];
int prefD[111111];
int prefUD[111111];

int sumL(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefL[r];
  else
    return add(prefL[r], MOD - prefL[l - 1]);
}

int sumR(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefR[r];
  else
    return add(prefR[r], MOD - prefR[l - 1]);
}

int sumU(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefU[r];
  else
    return add(prefU[r], MOD - prefU[l - 1]);
}

int sumD(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefD[r];
  else
    return add(prefD[r], MOD - prefD[l - 1]);
}

int sumUD(int l, int r) {
  if (l > r)
    return 0;
  if (l == 0)
    return prefUD[r];
  else
    return add(prefUD[r], MOD - prefUD[l - 1]);
}

int solve(int r, int c) { return choose(r + c - 1, r); }

void calcL(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefL[i] = (s[i] == '1');
    if (i > 0)
      prefL[i] += prefL[i - 1];
  }
}

void calcR(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefR[i] = (s[i] == '1');
    if (i > 0)
      prefR[i] += prefR[i - 1];
  }
}

void calcU(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefU[i] = (s[i] == '1');
    if (i > 0)
      prefU[i] += prefU[i - 1];
  }
}

void calcD(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefD[i] = (s[i] == '1');
    if (i > 0)
      prefD[i] += prefD[i - 1];
  }
}

void calcUD(string s) {
  for (int i = 0; i < s.length(); i++) {
    prefUD[i] = (s[i] == '1');
    if (i > 0)
      prefUD[i] += prefUD[i - 1];
  }
}

int dpl[222222];
int dpr[222222];

int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  init(533333);
  int n, m;
  cin >> n >> m;
  string L, R, U, D;
  cin >> L;
  cin >> R;
  cin >> U;
  cin >> D;
  string sud;
  for (int i = 0; i < U.length(); i++)
    sud += char('0' + ((U[i] - '0') & (D[i] - '0')));
  calcL(L);
  calcR(R);
  calcU(U);
  calcD(D);
  calcUD(sud);
  if (sumL(0, n - 1) == 0 && sumR(0, n - 1) == 0 && sumU(0, m - 1) == 0 &&
      sumD(0, m - 1) == 0) {
    cout << 1 << '\n';
    return 0;
  }
  for (int l = 0; l < m; l++) {
    int ltot = sumL(0, n - 1);
    int c1 = sumU(0, l - 1);
    int c2 = sumD(0, l - 1);
    if (l == 0)
      dpl[l] = 1;
    else
      dpl[l] = choose(c1 + c2 - 1 + ltot, c1 + c2);
  }
  for (int r = 0; r < m; r++) {
    int ltot = sumR(0, n - 1);
    int c1 = sumU(r + 1, m - 1);
    int c2 = sumD(r + 1, m - 1);
    if (r == m - 1)
      dpr[r] = 1;
    else
      dpr[r] = choose(c1 + c2 - 1 + ltot, c1 + c2);
  }
  int ans = 0;
  for (int l = 0; l < m; l++) {
    int r = l;
    int coeff = mult(pow2[sumUD(l + 1, r - 1)],
                     ((U[l] == '1') + (D[l] == '1')) *
                         (l == r ? 1 : ((U[r] == '1') + (D[r] == '1'))));
    if (coeff == 0)
      continue;
    int res1 = dpl[l];
    int res2 = dpr[r];
    ans = add(ans, mult(coeff, mult(res1, res2)));
  }
  for (int l = 0; l < m; l++) {
    dpl[l] = mult(dpl[l], ipow2[prefUD[l]]);
    dpl[l] = mult(dpl[l], (U[l] == '1') + (D[l] == '1'));
  }
  for (int r = 0; r < m; r++) {
    dpr[r] = mult(dpr[r], pow2[(r > 0 ? prefUD[r - 1] : 0)]);
    dpr[r] = mult(dpr[r], (U[r] == '1') + (D[r] == '1'));
  }
  int sum = 0;
  for (int l = 0; l + 1 < m; l++) {
    // solve for all r>l
    sum = add(sum, dpl[l]);
    ans = add(ans, mult(sum, dpr[l + 1]));
  }
  swap(U, L);
  swap(R, D);
  swap(n, m);
  sud = "";
  for (int i = 0; i < U.length(); i++)
    sud += char('0' + ((U[i] - '0') & (D[i] - '0')));
  calcL(L);
  calcR(R);
  calcU(U);
  calcD(D);
  calcUD(sud);
  for (int l = 0; l < m; l++) {
    int ltot = sumL(0, n - 1);
    int c1 = sumU(0, l - 1);
    int c2 = sumD(0, l - 1);
    if (l == 0)
      dpl[l] = 1;
    else
      dpl[l] = choose(c1 + c2 - 1 + ltot, c1 + c2);
  }
  for (int r = 0; r < m; r++) {
    int ltot = sumR(0, n - 1);
    int c1 = sumU(r + 1, m - 1);
    int c2 = sumD(r + 1, m - 1);
    if (r == m - 1)
      dpr[r] = 1;
    else
      dpr[r] = choose(c1 + c2 - 1 + ltot, c1 + c2);
  }
  for (int l = 0; l < m; l++) {
    int r = l;
    int coeff = mult(pow2[sumUD(l + 1, r - 1)],
                     ((U[l] == '1') + (D[l] == '1')) *
                         (l == r ? 1 : ((U[r] == '1') + (D[r] == '1'))));
    if (coeff == 0)
      continue;
    int res1 = dpl[l];
    int res2 = dpr[r];
    ans = add(ans, mult(coeff, mult(res1, res2)));
  }
  for (int l = 0; l < m; l++) {
    dpl[l] = mult(dpl[l], ipow2[prefUD[l]]);
    dpl[l] = mult(dpl[l], (U[l] == '1') + (D[l] == '1'));
  }
  for (int r = 0; r < m; r++) {
    dpr[r] = mult(dpr[r], pow2[(r > 0 ? prefUD[r - 1] : 0)]);
    dpr[r] = mult(dpr[r], (U[r] == '1') + (D[r] == '1'));
  }
  sum = 0;
  for (int l = 0; l + 1 < m; l++) {
    // solve for all r>l
    sum = add(sum, dpl[l]);
    ans = add(ans, mult(sum, dpr[l + 1]));
  }
  cout << ans << '\n';
}