Problem p03134 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;

using i64 = int64_t;

#define rep(i, x, y)                                                           \
  for (i64 i = i64(x), i##_max_for_repmacro = i64(y);                          \
       i < i##_max_for_repmacro; ++i)
#define debug(x) #x << "=" << (x)

#ifdef DEBUG
#define _GLIBCXX_DEBUG
#define print(x) std::cerr << debug(x) << " (L:" << __LINE__ << ")" << std::endl
#else
#define print(x)
#endif

template <i64 p> class fp {
public:
  i64 x;
  fp() : x(0) {}
  fp(i64 x_) : x((x_ % p + p) % p) {}
  fp operator+() const { return fp(x); }
  fp operator-() const { return fp(-x); }
  fp &operator+=(const fp &y) {
    x += y.x;
    if (x >= p)
      x -= p;
    return *this;
  }
  fp &operator-=(const fp &y) { return *this += -y; }
  fp &operator*=(const fp &y) {
    x = x * y.x % p;
    return *this;
  }
  fp &operator/=(const fp &y) { return *this *= fp(inverse(y.x)); }
  fp operator+(const fp &y) const { return fp(x) += y; }
  fp operator-(const fp &y) const { return fp(x) -= y; }
  fp operator*(const fp &y) const { return fp(x) *= y; }
  fp operator/(const fp &y) const { return fp(x) /= y; }
  bool operator==(const fp &y) const { return x == y.x; }
  bool operator!=(const fp &y) const { return !(*this == y); }
  i64 extgcd(i64 a, i64 b, i64 &x, i64 &y) {
    i64 d = a;
    if (b != 0) {
      d = extgcd(b, a % b, y, x);
      y -= (a / b) * x;
    } else {
      x = 1;
      y = 0;
    }
    return d;
  }
  i64 inverse(i64 a) {
    i64 x, y;
    extgcd(a, p, x, y);
    return (x % p + p) % p;
  }
};

template <i64 p> i64 abs(const fp<p> &x) { return x.x; }

template <i64 p> ostream &operator<<(ostream &os, const fp<p> &x) {
  os << x.x;
  return os;
}

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  os << "(" << p.first << ", " << p.second << ")";
  return os;
}

template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
  os << "[";
  for (const auto &v : vec) {
    os << v << ",";
  }
  os << "]";
  return os;
}

template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}

template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template <typename A, typename T, size_t size>
void fill(A (&ary)[size], const T &val) {
  fill((T *)ary, (T *)(ary + size), val);
}

// x未満の要素の個数を返す
template <typename T> i64 count_less(const vector<T> &v, T x) {
  return lower_bound(begin(v), end(v), x) - begin(v);
}

// x以下の要素の個数を返す
template <typename T> i64 count_less_or_equal(const vector<T> &v, T x) {
  return upper_bound(begin(v), end(v), x) - begin(v);
}

// xより大きい要素の個数を返す
template <typename T> i64 count_greater(const vector<T> &v, T x) {
  return end(v) - upper_bound(begin(v), end(v), x);
}

// x以上の要素の個数を返す
template <typename T> i64 count_greater_or_equal(const vector<T> &v, T x) {
  return end(v) - lower_bound(begin(v), end(v), x);
}

// x未満の要素のうち最大のものを返す
template <typename T> T max_less(const vector<T> &v, T x) {
  return *(lower_bound(begin(v), end(v), x) - 1);
}

// x以下の要素のうち最大のものを返す
template <typename T> T max_less_or_equal(const vector<T> &v, T x) {
  return *(upper_bound(begin(v), end(v), x) - 1);
}

// xより大きい要素のうち最小のものを返す
template <typename T> T min_greater(const vector<T> &v, T x) {
  return *upper_bound(begin(v), end(v), x);
}

// x以上の要素のうち最小のものを返す
template <typename T> T min_greater_or_equal(const vector<T> &v, T x) {
  return *lower_bound(begin(v), end(v), x);
}

constexpr int inf = 1.01e9;
constexpr i64 inf64 = 4.01e18;
constexpr double eps = 1e-9;

void solve() {
  constexpr i64 mod = 998244353;

  string S;
  cin >> S;

  /*
  set<string> st;
  function<void(vector<vector<int>>, int, string)> dfs=[&](vector<vector<int>>
  v, int i, string res){ if(v.empty()){ st.insert(res); return;
      }

      if(i==v.size()){
          if(v.back().empty()){
              v.pop_back();
          }
          dfs(v,0,res);
          return;
      }

      rep(j,0,v[i].size()){
          auto nv=v;
          auto nres=res;
          if(i==0){
              nres+='0'+nv[i][j];
          }else{
              nv[i-1].emplace_back(nv[i][j]);
          }
          nv[i].erase(begin(nv[i])+j);
          dfs(nv,i+1,nres);
      }
  };
*/
  const i64 N = S.size();

  function<void(vector<vector<int>> &, int, string &)> find_min =
      [&](vector<vector<int>> &v, int i, string &res) {
        while (!v.empty()) {
          if (i == v.size()) {
            if (v.back().empty()) {
              v.pop_back();
            }
            i = 0;
            continue;
          }

          sort(begin(v[i]), end(v[i]));
          if (i == 0) {
            res += '0' + v[i][0];
          } else {
            v[i - 1].emplace_back(v[i][0]);
          }
          v[i].erase(begin(v[i]));
          ++i;
        }
      };

  function<void(vector<vector<int>> &, int, string &)> find_max =
      [&](vector<vector<int>> &v, int i, string &res) {
        while (!v.empty()) {
          if (i == v.size()) {
            if (v.back().empty()) {
              v.pop_back();
            }
            i = 0;
            continue;
          }

          sort(rbegin(v[i]), rend(v[i]));
          if (i == 0) {
            res += '0' + v[i][0];
          } else {
            v[i - 1].emplace_back(v[i][0]);
          }
          v[i].erase(begin(v[i]));
          ++i;
        }
      };

  vector<vector<int>> v(N);
  rep(i, 0, N) {
    if (S[i] == '0') {
      v[i].emplace_back(0);
      v[i].emplace_back(0);
    } else if (S[i] == '1') {
      v[i].emplace_back(0);
      v[i].emplace_back(1);
    } else {
      v[i].emplace_back(1);
      v[i].emplace_back(1);
    }
  }

  string mini, maxi;
  {
    auto tv = v;
    find_min(tv, 0, mini);
  }
  {
    auto tv = v;
    find_max(tv, 0, maxi);
  }
  print(mini);
  print(maxi);

  vector<i64> rmin(N), bmin(N);
  {
    i64 r = 0, b = 0;
    rep(i, 0, N) {
      rep(j, 0, 2) {
        if (v[i][j] == 0)
          ++r;
        else
          ++b;
      }
      rmin[i] = max(i + 1 - b, i64(0));
      bmin[i] = max(i + 1 - r, i64(0));
    }
  }

  print(rmin);
  print(bmin);

  function<fp<mod>(string)> count = [&](string m) {
    constexpr i64 maxn = 2000;
    static fp<mod> dp[maxn * 2][2][maxn + 1]; // 桁, 境界か?, 使用したbの数
    fill_n((fp<mod> *)dp, maxn * 2 * 2 * (maxn + 1), fp<mod>(0));

    i64 sumb = 0;
    rep(i, 0, m.size()) if (m[i] == '1')++ sumb;

    if (m[0] == '0') {
      dp[0][1][0] = 1;
    } else {
      dp[0][0][0] = 1;
      dp[0][1][1] = 1;
    }

    rep(i, 0, m.size() - 1) {
      rep(j, 0, 2) {
        rep(k, 0, sumb + 1) {
          if (i < N) {
            i64 r = i + 1 - k;
            i64 b = k;
            if (r < rmin[i] or b < bmin[i])
              continue;
          }

          // r=0を置く
          if (m[i + 1] == '0') {
            if (j == 0) {
              // 既に境界より低い
              dp[i + 1][0][k] += dp[i][j][k];
            } else {
              dp[i + 1][1][k] += dp[i][j][k];
            }
          } else {
            dp[i + 1][0][k] += dp[i][j][k];
          }

          // sumb=1を置く
          if (k < sumb) {
            if (m[i + 1] == '0') {
              if (j == 0) {
                // 既に境界より低い
                dp[i + 1][0][k + 1] += dp[i][j][k];
              } else {
                // 境界を超える
              }
            } else {
              if (j == 0) {
                // 既に境界より低い
                dp[i + 1][0][k + 1] += dp[i][j][k];
              } else {
                // 境界にいる
                dp[i + 1][1][k + 1] += dp[i][j][k];
              }
            }
          }
        }
      }
    }

    return dp[m.size() - 1][0][sumb] + dp[m.size() - 1][1][sumb];
  };

  const auto ans = count(maxi) - count(mini) + 1;

  cout << ans << endl;
  /*
  #ifdef DEBUG
      dfs(v,0,"");
      print(st.size());
      for(auto str:st){
          cout << str << endl;
      }
  #endif
   */
}

int main() {
  std::cin.tie(0);
  std::ios::sync_with_stdio(false);
  cout.setf(ios::fixed);
  cout.precision(16);
  solve();
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
using namespace std;

using i64 = int64_t;

#define rep(i, x, y)                                                           \
  for (i64 i = i64(x), i##_max_for_repmacro = i64(y);                          \
       i < i##_max_for_repmacro; ++i)
#define debug(x) #x << "=" << (x)

#ifdef DEBUG
#define _GLIBCXX_DEBUG
#define print(x) std::cerr << debug(x) << " (L:" << __LINE__ << ")" << std::endl
#else
#define print(x)
#endif

template <i64 p> class fp {
public:
  i64 x;
  fp() : x(0) {}
  fp(i64 x_) : x((x_ % p + p) % p) {}
  fp operator+() const { return fp(x); }
  fp operator-() const { return fp(-x); }
  fp &operator+=(const fp &y) {
    x += y.x;
    if (x >= p)
      x -= p;
    return *this;
  }
  fp &operator-=(const fp &y) { return *this += -y; }
  fp &operator*=(const fp &y) {
    x = x * y.x % p;
    return *this;
  }
  fp &operator/=(const fp &y) { return *this *= fp(inverse(y.x)); }
  fp operator+(const fp &y) const { return fp(x) += y; }
  fp operator-(const fp &y) const { return fp(x) -= y; }
  fp operator*(const fp &y) const { return fp(x) *= y; }
  fp operator/(const fp &y) const { return fp(x) /= y; }
  bool operator==(const fp &y) const { return x == y.x; }
  bool operator!=(const fp &y) const { return !(*this == y); }
  i64 extgcd(i64 a, i64 b, i64 &x, i64 &y) {
    i64 d = a;
    if (b != 0) {
      d = extgcd(b, a % b, y, x);
      y -= (a / b) * x;
    } else {
      x = 1;
      y = 0;
    }
    return d;
  }
  i64 inverse(i64 a) {
    i64 x, y;
    extgcd(a, p, x, y);
    return (x % p + p) % p;
  }
};

template <i64 p> i64 abs(const fp<p> &x) { return x.x; }

template <i64 p> ostream &operator<<(ostream &os, const fp<p> &x) {
  os << x.x;
  return os;
}

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  os << "(" << p.first << ", " << p.second << ")";
  return os;
}

template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
  os << "[";
  for (const auto &v : vec) {
    os << v << ",";
  }
  os << "]";
  return os;
}

template <typename T> bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}

template <typename T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

template <typename A, typename T, size_t size>
void fill(A (&ary)[size], const T &val) {
  fill((T *)ary, (T *)(ary + size), val);
}

// x未満の要素の個数を返す
template <typename T> i64 count_less(const vector<T> &v, T x) {
  return lower_bound(begin(v), end(v), x) - begin(v);
}

// x以下の要素の個数を返す
template <typename T> i64 count_less_or_equal(const vector<T> &v, T x) {
  return upper_bound(begin(v), end(v), x) - begin(v);
}

// xより大きい要素の個数を返す
template <typename T> i64 count_greater(const vector<T> &v, T x) {
  return end(v) - upper_bound(begin(v), end(v), x);
}

// x以上の要素の個数を返す
template <typename T> i64 count_greater_or_equal(const vector<T> &v, T x) {
  return end(v) - lower_bound(begin(v), end(v), x);
}

// x未満の要素のうち最大のものを返す
template <typename T> T max_less(const vector<T> &v, T x) {
  return *(lower_bound(begin(v), end(v), x) - 1);
}

// x以下の要素のうち最大のものを返す
template <typename T> T max_less_or_equal(const vector<T> &v, T x) {
  return *(upper_bound(begin(v), end(v), x) - 1);
}

// xより大きい要素のうち最小のものを返す
template <typename T> T min_greater(const vector<T> &v, T x) {
  return *upper_bound(begin(v), end(v), x);
}

// x以上の要素のうち最小のものを返す
template <typename T> T min_greater_or_equal(const vector<T> &v, T x) {
  return *lower_bound(begin(v), end(v), x);
}

constexpr int inf = 1.01e9;
constexpr i64 inf64 = 4.01e18;
constexpr double eps = 1e-9;

void solve() {
  constexpr i64 mod = 998244353;

  string S;
  cin >> S;

  /*
  set<string> st;
  function<void(vector<vector<int>>, int, string)> dfs=[&](vector<vector<int>>
  v, int i, string res){ if(v.empty()){ st.insert(res); return;
      }

      if(i==v.size()){
          if(v.back().empty()){
              v.pop_back();
          }
          dfs(v,0,res);
          return;
      }

      rep(j,0,v[i].size()){
          auto nv=v;
          auto nres=res;
          if(i==0){
              nres+='0'+nv[i][j];
          }else{
              nv[i-1].emplace_back(nv[i][j]);
          }
          nv[i].erase(begin(nv[i])+j);
          dfs(nv,i+1,nres);
      }
  };
*/
  const i64 N = S.size();

  function<void(vector<vector<int>> &, int, string &)> find_min =
      [&](vector<vector<int>> &v, int i, string &res) {
        while (!v.empty()) {
          if (i == v.size()) {
            if (v.back().empty()) {
              v.pop_back();
            }
            i = 0;
            continue;
          }

          sort(begin(v[i]), end(v[i]));
          if (i == 0) {
            res += '0' + v[i][0];
          } else {
            v[i - 1].emplace_back(v[i][0]);
          }
          v[i].erase(begin(v[i]));
          ++i;
        }
      };

  function<void(vector<vector<int>> &, int, string &)> find_max =
      [&](vector<vector<int>> &v, int i, string &res) {
        while (!v.empty()) {
          if (i == v.size()) {
            if (v.back().empty()) {
              v.pop_back();
            }
            i = 0;
            continue;
          }

          sort(rbegin(v[i]), rend(v[i]));
          if (i == 0) {
            res += '0' + v[i][0];
          } else {
            v[i - 1].emplace_back(v[i][0]);
          }
          v[i].erase(begin(v[i]));
          ++i;
        }
      };

  vector<vector<int>> v(N);
  rep(i, 0, N) {
    if (S[i] == '0') {
      v[i].emplace_back(0);
      v[i].emplace_back(0);
    } else if (S[i] == '1') {
      v[i].emplace_back(0);
      v[i].emplace_back(1);
    } else {
      v[i].emplace_back(1);
      v[i].emplace_back(1);
    }
  }

  string mini, maxi;
  {
    auto tv = v;
    find_min(tv, 0, mini);
  }
  {
    auto tv = v;
    find_max(tv, 0, maxi);
  }
  print(mini);
  print(maxi);

  vector<i64> rmin(N), bmin(N);
  {
    i64 r = 0, b = 0;
    rep(i, 0, N) {
      rep(j, 0, 2) {
        if (v[i][j] == 0)
          ++r;
        else
          ++b;
      }
      rmin[i] = max(i + 1 - b, i64(0));
      bmin[i] = max(i + 1 - r, i64(0));
    }
  }

  print(rmin);
  print(bmin);

  function<fp<mod>(string)> count = [&](string m) {
    constexpr i64 maxn = 2000;
    static fp<mod> dp[maxn * 2][2][2 * maxn + 1]; // 桁, 境界か?, 使用したbの数
    fill_n((fp<mod> *)dp, maxn * 2 * 2 * (2 * maxn + 1), fp<mod>(0));

    i64 sumb = 0;
    rep(i, 0, m.size()) if (m[i] == '1')++ sumb;

    if (m[0] == '0') {
      dp[0][1][0] = 1;
    } else {
      dp[0][0][0] = 1;
      dp[0][1][1] = 1;
    }

    rep(i, 0, m.size() - 1) {
      rep(j, 0, 2) {
        rep(k, 0, sumb + 1) {
          if (i < N) {
            i64 r = i + 1 - k;
            i64 b = k;
            if (r < rmin[i] or b < bmin[i])
              continue;
          }

          // r=0を置く
          if (m[i + 1] == '0') {
            if (j == 0) {
              // 既に境界より低い
              dp[i + 1][0][k] += dp[i][j][k];
            } else {
              dp[i + 1][1][k] += dp[i][j][k];
            }
          } else {
            dp[i + 1][0][k] += dp[i][j][k];
          }

          // sumb=1を置く
          if (k < sumb) {
            if (m[i + 1] == '0') {
              if (j == 0) {
                // 既に境界より低い
                dp[i + 1][0][k + 1] += dp[i][j][k];
              } else {
                // 境界を超える
              }
            } else {
              if (j == 0) {
                // 既に境界より低い
                dp[i + 1][0][k + 1] += dp[i][j][k];
              } else {
                // 境界にいる
                dp[i + 1][1][k + 1] += dp[i][j][k];
              }
            }
          }
        }
      }
    }

    return dp[m.size() - 1][0][sumb] + dp[m.size() - 1][1][sumb];
  };

  const auto ans = count(maxi) - count(mini) + 1;

  cout << ans << endl;
  /*
  #ifdef DEBUG
      dfs(v,0,"");
      print(st.size());
      for(auto str:st){
          cout << str << endl;
      }
  #endif
   */
}

int main() {
  std::cin.tie(0);
  std::ios::sync_with_stdio(false);
  cout.setf(ios::fixed);
  cout.precision(16);
  solve();
  return 0;
}