Problem p02653 (C++) — buggy submission, verdict: Runtime Error


#if 1
#include <algorithm>
#include <array>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <cstdint>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

auto &in = std::cin;
auto &out = std::cout;
#define all_range(C) std::begin(C), std::end(C)
const double PI =
    3.141592653589793238462643383279502884197169399375105820974944;

template <typename Arithmetic, typename Integral>
std::enable_if_t<std::is_unsigned<Integral>::value, Arithmetic>
ipow(Arithmetic bace, Integral n) {
  // 繰り返し二条法
  auto res = (Arithmetic)(1);
  while (n > 0) {
    if (n & 1)
      res *= bace;
    bace *= bace;
    n >>= 1;
  }
  return res;
}
constexpr bool is_prime(uint32_t N) {
  if (N <= 1) {
    return false;
  }
  for (size_t i = 2; i * i <= N; ++i) {
    if (N % i == 0) {
      return false;
    }
  }
  return true;
}
template <uint64_t MOD> class mint_base;
// mint_base_base型用の累乗関数
template <uint64_t MOD>
constexpr mint_base<MOD> m_pow(mint_base<MOD> x, uint64_t n) noexcept;
// mod計算を自動で行う整数テンプレートクラス
template <uint64_t MOD_ = 1000000007> class mint_base {
public:
  static constexpr auto MOD = MOD_;
  static_assert(!(MOD <= 2), "MOD cannot be below 2.");
  static_assert(MOD <= (0xFFFFFFFFFFFFFFFF / 2),
                "MOD is too big"); // 加算してオーバーフローしない
  static_assert(MOD <= 0xFFFFFFFF,
                "MOD is too big"); // 乗算してオーバーフローしない
  constexpr mint_base<MOD>
  operator+(const mint_base<MOD> &other) const noexcept {
    auto v = *this;
    return v += other;
  }
  constexpr mint_base<MOD>
  operator-(const mint_base<MOD> &other) const noexcept {
    auto v = *this;
    return v -= other;
  }
  constexpr mint_base<MOD>
  operator*(const mint_base<MOD> &other) const noexcept {
    auto v = *this;
    return v *= other;
  }
  constexpr auto operator/(const mint_base<MOD> &other) const noexcept {
    auto v = *this;
    return v /= other;
  }
  constexpr mint_base<MOD> &operator+=(const mint_base<MOD> &other) noexcept {
    a += other.a;
    if (MOD <= a) {
      a -= MOD;
    };
    return *this;
  }
  constexpr mint_base<MOD> &operator-=(const mint_base<MOD> &other) noexcept {
    if (a >= other.a) {
      a -= other.a;
    } else {
      a = (a + MOD) - other.a;
    }
    return *this;
  }
  constexpr mint_base<MOD> &operator*=(const mint_base<MOD> &other) noexcept {
#if 1
    a *= other.a;
    a %= MOD;
#else
    // MOD <= (MAXUINT64 / 2)条件下
    uint64_t b = other.a, v = 0;
    while (b > 0) {
      if (b & 1) {
        v += a;
        if (v >= MOD)
          v -= MOD;
      }
      a += a;
      if (MOD <= a)
        a -= MOD;
      b >>= 1;
    }
    a = v;
#endif
    return *this;
  }
  constexpr mint_base<MOD> &operator/=(const mint_base<MOD> &other) noexcept {
    return *this *= ~other;
  }
  constexpr mint_base<MOD> operator+() const noexcept { return *this; }
  constexpr mint_base<MOD> operator-() const noexcept {
    return {MOD - a, mod_value_tag{}};
  }
  constexpr mint_base<MOD> &operator++() noexcept {
    if (MOD <= ++a) {
      a = 0;
    };
    return *this;
  }
  constexpr mint_base<MOD> &operator--() noexcept {
    if (a <= 0) {
      a = MOD;
    };
    --a;
    return *this;
  }
  constexpr mint_base<MOD> operator++(int) noexcept {
    auto tmp = *this;
    ++*this;
    return tmp;
  }
  constexpr mint_base<MOD> operator--(int) noexcept {
    auto tmp = *this;
    --*this;
    return tmp;
  }
  constexpr mint_base<MOD> operator~() const noexcept {
    return ipow(*this, e_phi - 1);
  }
  constexpr mint_base<MOD> &operator=(const mint_base<MOD> &other) noexcept {
    a = other.a;
    return *this;
  }
  constexpr explicit operator uint64_t() const noexcept { return a; }
  constexpr explicit operator unsigned() const noexcept { return (unsigned)a; }
  static constexpr uint64_t getmod() noexcept { return MOD; }
  constexpr mint_base(uint64_t a_) noexcept : a(a_ % MOD) {}
  constexpr mint_base() noexcept : a(0) {}
  struct mod_value_tag {};
  constexpr mint_base(uint64_t a_, mod_value_tag) : a(a_) {}

private:
  static constexpr uint64_t get_e_phi() noexcept {
    // オイラー値の導出
    uint64_t temp = MOD;
    uint64_t m_ = MOD;
    for (uint64_t i = 2; i * i <= m_; ++i) {
      if (m_ % i == 0) {
        temp = temp / i * (i - 1);
        for (; m_ % i == 0; m_ /= i)
          ;
      }
    }
    if (m_ != 1)
      temp = temp / m_ * (m_ - 1);
    return temp;
  }
  static constexpr uint64_t e_phi = get_e_phi(); // オイラー値
  uint64_t a;
};
// mint_base型のstreamへの出力
template <uint64_t MOD>
std::ostream &operator<<(std::ostream &os, mint_base<MOD> i) {
  os << (uint64_t)i;
  return os;
}
// mint_base型のstreamからの入力
template <uint64_t MOD>
std::istream &operator>>(std::istream &is, mint_base<MOD> &i) {
  uint64_t tmp;
  is >> tmp;
  i = tmp;
  return is;
}
typedef mint_base<> mint;
namespace mint_literal {
constexpr mint operator""_mi(unsigned long long x) noexcept { return mint(x); }
} // namespace mint_literal
using namespace mint_literal;

int32_t N, A, B;

mint pow2[5100];
mint dp5[5100][5100];
bool used5[5100][5100];
mint func4(int i, int a_max, int onB);
mint func5(int ic, int icend) {
  if (ic >= icend) {
    return 0_mi;
  }
  if (N < icend) {
    return 0_mi;
  }

  auto &memo = dp5[ic][icend];
  if (used5[ic][icend]) {
    return memo;
  }
  used5[ic][icend] = true;

  memo = func4(ic + 1, ic + A - 1, 0);
  memo += func5(ic + 1, icend);

  return memo;
}
mint dp4[5100][5100][2];
bool used4[5100][5100][2];
mint func4(int i, int a_max, int onB) {
  if (N <= a_max) {
    return 0_mi;
  }
  if (i > N) {
    return 0_mi;
  }
  if (a_max < i) {
    return pow2[N - i];
  }

  auto &memo = dp4[i][a_max][onB];
  if (used4[i][a_max][onB]) {
    return memo;
  }
  used4[i][a_max][onB] = true;

  if (onB != 0) {
    return memo = func4(i + 1, a_max, 0) + func4(i + 1, a_max, 1);
  }

  memo = func4(i + 1, a_max, 0);
  // for (size_t c = 1; c < B; c++)
  //{
  //	memo += func4(i + c + 1, i + c + A-1, 0);
  // }
  memo += func5(i + 1, std::min(i + B, N));
  memo += func4(i + B, a_max, 1);
  return memo;
}

// Aは[a_end-A, a_end)
mint func(int i, int a_end, bool prev_is_b) {
  static mint dp[5100][5100][2];
  static bool used[5100][5100][2];
  if (N < i || N + 1 <= a_end) {
    return 0_mi; // 入りきってない
  }
  if (a_end <= i) {
    return pow2[N - i]; // あとは自由
  }

  auto &memo = dp[i][a_end][prev_is_b ? 0 : 1];
  if (used[i][a_end][prev_is_b ? 0 : 1]) {
    return memo;
  }
  used[i][a_end][prev_is_b ? 0 : 1] = true;

  mint res = 0; // mintは自動MODの整数型

  if (prev_is_b) {
    // Bの終わった直後
    res += func(i + 1, a_end, false); // 0を置く
    res += func(i + 1, a_end, true);  // 1を置く
  } else {
    // Aの中
    res += func(i + 1, a_end, false); // 0を置く
    for (int k = 1; k < B; k++) {     // 1をk個と0を一個置く
      // Bの途中で0を置く
      res += func(i + k + 1, i + k + A, false);
      // ↑最後に0を置いたのでAの中にいる
    }
    res += func(i + B, a_end, true); // 1をB個
  }
  return memo = res;
}

// Aは[a_end-A, a_end), Bは[b_end-B, b_end)
mint func_ON3(int i, int a_end, int b_end) {
  static mint dp[100][100][100];
  static bool used[100][100][100];
  if (N + 1 <= a_end || N + 1 <= b_end) {
    return 0_mi; // 入りきってない
  }
  if (a_end <= i && b_end <= i) {
    return pow2[N - i]; // あとは自由
  }

  auto &memo = dp[i][a_end][b_end];
  if (used[i][a_end][b_end]) {
    return memo;
  }
  used[i][a_end][b_end] = true;

  mint res = 0;                               // mintは自動MODの整数型
  if (i < b_end) {                            // Bの中
    res += func_ON3(i + 1, i + A, 0);         // 0を置く
    res += func_ON3(i + 1, a_end, b_end);     // 1を置く
  } else if (B <= b_end && i == b_end) {      // Bの終わった直後
    res += func_ON3(i + 1, a_end, b_end);     // 0を置く
    res += func_ON3(i + 1, a_end, b_end + 1); // 1を置く
  } else {                                    // Aの中
    res += func_ON3(i + 1, a_end, b_end);     // 0を置く
    res += func_ON3(i + 1, a_end, i + B);     // 1を置く
  }
  return memo = res;
}

int main() {
  using std::endl;
  in.sync_with_stdio(false);
  out.sync_with_stdio(false);
  in.tie(nullptr);
  out.tie(nullptr);

  pow2[0] = 1;
  for (size_t i = 0; i < 5050; i++) {
    pow2[i + 1] = pow2[i] + pow2[i];
  }

  in >> N >> A >> B;
  if (A < B) {
    std::swap(A, B);
  }
  if (A == 1) {
    out << pow2[N] << endl;
    return 0;
  }
  if (N < 90) {
    out << func(0, A, false) << endl;
    return 0;
  }
  // if (N < 90) {
  //	out << func_ON3(0, A, 0) << endl;
  //	return 0;
  // }

  // out <<
  //	func1(0, 0, 0) +
  //	func2(0, 0, 0) * (func3(A) - 1_mi) << endl;
  out << func4(0, A - 1, 0) << endl;

  return 0;
}
#endif


Error: -11

Fixed submission:


#if 1
#include <algorithm>
#include <array>
#include <assert.h>
#include <bitset>
#include <cmath>
#include <cstdint>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

auto &in = std::cin;
auto &out = std::cout;
#define all_range(C) std::begin(C), std::end(C)
const double PI =
    3.141592653589793238462643383279502884197169399375105820974944;

template <typename Arithmetic, typename Integral>
std::enable_if_t<std::is_unsigned<Integral>::value, Arithmetic>
ipow(Arithmetic bace, Integral n) {
  // 繰り返し二条法
  auto res = (Arithmetic)(1);
  while (n > 0) {
    if (n & 1)
      res *= bace;
    bace *= bace;
    n >>= 1;
  }
  return res;
}
constexpr bool is_prime(uint32_t N) {
  if (N <= 1) {
    return false;
  }
  for (size_t i = 2; i * i <= N; ++i) {
    if (N % i == 0) {
      return false;
    }
  }
  return true;
}
template <uint64_t MOD> class mint_base;
// mint_base_base型用の累乗関数
template <uint64_t MOD>
constexpr mint_base<MOD> m_pow(mint_base<MOD> x, uint64_t n) noexcept;
// mod計算を自動で行う整数テンプレートクラス
template <uint64_t MOD_ = 1000000007> class mint_base {
public:
  static constexpr auto MOD = MOD_;
  static_assert(!(MOD <= 2), "MOD cannot be below 2.");
  static_assert(MOD <= (0xFFFFFFFFFFFFFFFF / 2),
                "MOD is too big"); // 加算してオーバーフローしない
  static_assert(MOD <= 0xFFFFFFFF,
                "MOD is too big"); // 乗算してオーバーフローしない
  constexpr mint_base<MOD>
  operator+(const mint_base<MOD> &other) const noexcept {
    auto v = *this;
    return v += other;
  }
  constexpr mint_base<MOD>
  operator-(const mint_base<MOD> &other) const noexcept {
    auto v = *this;
    return v -= other;
  }
  constexpr mint_base<MOD>
  operator*(const mint_base<MOD> &other) const noexcept {
    auto v = *this;
    return v *= other;
  }
  constexpr auto operator/(const mint_base<MOD> &other) const noexcept {
    auto v = *this;
    return v /= other;
  }
  constexpr mint_base<MOD> &operator+=(const mint_base<MOD> &other) noexcept {
    a += other.a;
    if (MOD <= a) {
      a -= MOD;
    };
    return *this;
  }
  constexpr mint_base<MOD> &operator-=(const mint_base<MOD> &other) noexcept {
    if (a >= other.a) {
      a -= other.a;
    } else {
      a = (a + MOD) - other.a;
    }
    return *this;
  }
  constexpr mint_base<MOD> &operator*=(const mint_base<MOD> &other) noexcept {
#if 1
    a *= other.a;
    a %= MOD;
#else
    // MOD <= (MAXUINT64 / 2)条件下
    uint64_t b = other.a, v = 0;
    while (b > 0) {
      if (b & 1) {
        v += a;
        if (v >= MOD)
          v -= MOD;
      }
      a += a;
      if (MOD <= a)
        a -= MOD;
      b >>= 1;
    }
    a = v;
#endif
    return *this;
  }
  constexpr mint_base<MOD> &operator/=(const mint_base<MOD> &other) noexcept {
    return *this *= ~other;
  }
  constexpr mint_base<MOD> operator+() const noexcept { return *this; }
  constexpr mint_base<MOD> operator-() const noexcept {
    return {MOD - a, mod_value_tag{}};
  }
  constexpr mint_base<MOD> &operator++() noexcept {
    if (MOD <= ++a) {
      a = 0;
    };
    return *this;
  }
  constexpr mint_base<MOD> &operator--() noexcept {
    if (a <= 0) {
      a = MOD;
    };
    --a;
    return *this;
  }
  constexpr mint_base<MOD> operator++(int) noexcept {
    auto tmp = *this;
    ++*this;
    return tmp;
  }
  constexpr mint_base<MOD> operator--(int) noexcept {
    auto tmp = *this;
    --*this;
    return tmp;
  }
  constexpr mint_base<MOD> operator~() const noexcept {
    return ipow(*this, e_phi - 1);
  }
  constexpr mint_base<MOD> &operator=(const mint_base<MOD> &other) noexcept {
    a = other.a;
    return *this;
  }
  constexpr explicit operator uint64_t() const noexcept { return a; }
  constexpr explicit operator unsigned() const noexcept { return (unsigned)a; }
  static constexpr uint64_t getmod() noexcept { return MOD; }
  constexpr mint_base(uint64_t a_) noexcept : a(a_ % MOD) {}
  constexpr mint_base() noexcept : a(0) {}
  struct mod_value_tag {};
  constexpr mint_base(uint64_t a_, mod_value_tag) : a(a_) {}

private:
  static constexpr uint64_t get_e_phi() noexcept {
    // オイラー値の導出
    uint64_t temp = MOD;
    uint64_t m_ = MOD;
    for (uint64_t i = 2; i * i <= m_; ++i) {
      if (m_ % i == 0) {
        temp = temp / i * (i - 1);
        for (; m_ % i == 0; m_ /= i)
          ;
      }
    }
    if (m_ != 1)
      temp = temp / m_ * (m_ - 1);
    return temp;
  }
  static constexpr uint64_t e_phi = get_e_phi(); // オイラー値
  uint64_t a;
};
// mint_base型のstreamへの出力
template <uint64_t MOD>
std::ostream &operator<<(std::ostream &os, mint_base<MOD> i) {
  os << (uint64_t)i;
  return os;
}
// mint_base型のstreamからの入力
template <uint64_t MOD>
std::istream &operator>>(std::istream &is, mint_base<MOD> &i) {
  uint64_t tmp;
  is >> tmp;
  i = tmp;
  return is;
}
typedef mint_base<> mint;
namespace mint_literal {
constexpr mint operator""_mi(unsigned long long x) noexcept { return mint(x); }
} // namespace mint_literal
using namespace mint_literal;

int32_t N, A, B;

mint pow2[5100];
mint dp5[5100][5100];
bool used5[5100][5100];
mint func4(int i, int a_max, int onB);
mint func5(int ic, int icend) {
  if (ic >= icend) {
    return 0_mi;
  }

  auto &memo = dp5[ic][icend];
  if (used5[ic][icend]) {
    return memo;
  }
  used5[ic][icend] = true;

  memo = func4(ic + 1, ic + A - 1, 0);
  memo += func5(ic + 1, icend);

  return memo;
}
mint dp4[5100][5100][2];
bool used4[5100][5100][2];
mint func4(int i, int a_max, int onB) {
  if (N <= a_max) {
    return 0_mi;
  }
  if (a_max < i) {
    return pow2[N - i];
  }
  if (i >= N) {
    return 0_mi;
  }

  auto &memo = dp4[i][a_max][onB];
  if (used4[i][a_max][onB]) {
    return memo;
  }
  used4[i][a_max][onB] = true;

  if (onB != 0) {
    return memo = func4(i + 1, a_max, 0) + func4(i + 1, a_max, 1);
  }

  memo = func4(i + 1, a_max, 0);
  // for (size_t c = 1; c < B; c++)
  //{
  //	memo += func4(i + c + 1, i + c + A-1, 0);
  // }
  memo += func5(i + 1, std::min(i + B, N));
  memo += func4(i + B, a_max, 1);
  return memo;
}

// Aは[a_end-A, a_end)
mint func(int i, int a_end, bool prev_is_b) {
  static mint dp[5100][5100][2];
  static bool used[5100][5100][2];
  if (N < i || N + 1 <= a_end) {
    return 0_mi; // 入りきってない
  }
  if (a_end <= i) {
    return pow2[N - i]; // あとは自由
  }
  assert(i <= N);

  auto &memo = dp[i][a_end][prev_is_b ? 0 : 1];
  if (used[i][a_end][prev_is_b ? 0 : 1]) {
    return memo;
  }
  used[i][a_end][prev_is_b ? 0 : 1] = true;

  mint res = 0; // mintは自動MODの整数型

  if (prev_is_b) {
    // Bの終わった直後
    res += func(i + 1, a_end, false); // 0を置く
    res += func(i + 1, a_end, true);  // 1を置く
  } else {
    // Aの中
    res += func(i + 1, a_end, false); // 0を置く
    for (int k = 1; k < B; k++) {     // 1をk個と0を一個置く
      // Bの途中で0を置く
      res += func(i + k + 1, i + k + A, false);
      // ↑最後に0を置いたのでAの中にいる
    }
    res += func(i + B, a_end, true); // 1をB個
  }
  return memo = res;
}

// Aは[a_end-A, a_end), Bは[b_end-B, b_end)
mint func_ON3(int i, int a_end, int b_end) {
  static mint dp[100][100][100];
  static bool used[100][100][100];
  if (N + 1 <= a_end || N + 1 <= b_end) {
    return 0_mi; // 入りきってない
  }
  if (a_end <= i && b_end <= i) {
    return pow2[N - i]; // あとは自由
  }

  auto &memo = dp[i][a_end][b_end];
  if (used[i][a_end][b_end]) {
    return memo;
  }
  used[i][a_end][b_end] = true;

  mint res = 0;                               // mintは自動MODの整数型
  if (i < b_end) {                            // Bの中
    res += func_ON3(i + 1, i + A, 0);         // 0を置く
    res += func_ON3(i + 1, a_end, b_end);     // 1を置く
  } else if (B <= b_end && i == b_end) {      // Bの終わった直後
    res += func_ON3(i + 1, a_end, b_end);     // 0を置く
    res += func_ON3(i + 1, a_end, b_end + 1); // 1を置く
  } else {                                    // Aの中
    res += func_ON3(i + 1, a_end, b_end);     // 0を置く
    res += func_ON3(i + 1, a_end, i + B);     // 1を置く
  }
  return memo = res;
}

int main() {
  using std::endl;
  in.sync_with_stdio(false);
  out.sync_with_stdio(false);
  in.tie(nullptr);
  out.tie(nullptr);

  pow2[0] = 1;
  for (size_t i = 0; i < 5050; i++) {
    pow2[i + 1] = pow2[i] + pow2[i];
  }

  in >> N >> A >> B;
  if (A < B) {
    std::swap(A, B);
  }
  if (A == 1) {
    out << pow2[N] << endl;
    return 0;
  }
  if (N < 90) {
    out << func(0, A, false) << endl;
    return 0;
  }

  // out <<
  //	func1(0, 0, 0) +
  //	func2(0, 0, 0) * (func3(A) - 1_mi) << endl;
  out << func4(0, A - 1, 0) << endl;

  return 0;
}
#endif