Problem p03056 (C++)

Buggy submission (status: Runtime Error):
// includes {{{
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <tuple>
#include <vector>
// #include<deque>
// #include<multiset>
#include <cstring>
// #include<bits/stdc++.h>
// }}}
using namespace std;
using ll = long long;

string s[185];
const int C = 16;

int dp[2][185 + 1][185 + 1][185 + 1];
int h, w;

// accum2D range2D range2Dloop {{{
#include <type_traits>
using loop2d_int = long long;
template <class T> void accum2D(T &val, int h, int w) {
  for (int i = 1; i < h; i++)
    for (int j = 0; j < w; j++)
      val[i][j] += val[i - 1][j];
  for (int i = 0; i < h; i++)
    for (int j = 1; j < w; j++)
      val[i][j] += val[i][j - 1];
}

template <class T,
          class V = typename std::remove_reference<decltype(T()[0][0])>::type>
V range2D(T &val, int y1, int x1, int y2, int x2, int h, int w) {
  if (y2 >= h)
    y2 = h - 1;
  if (x2 >= w)
    x2 = w - 1;
  if (y1 > y2 || x1 > x2)
    return static_cast<V>(0);
  V res(val[y2][x2]);
  if (y1 - 1 >= 0)
    res -= val[y1 - 1][x2];
  if (x1 - 1 >= 0)
    res -= val[y2][x1 - 1];
  if (y1 - 1 >= 0 && x1 - 1 >= 0)
    res += val[y1 - 1][x1 - 1];
  return res;
}

template <class T,
          class V = typename std::remove_reference<decltype(T()[0][0])>::type>
auto range2Dloop(T &val, loop2d_int ty1, loop2d_int tx1, loop2d_int y2,
                 loop2d_int x2, int h, int w) {
  if (ty1 > y2 || tx1 > x2)
    return static_cast<V>(0);

  loop2d_int y1 = ty1 % h;
  if (y1 < 0)
    y1 += h;
  loop2d_int x1 = tx1 % w;
  if (x1 < 0)
    x1 += w;

  y2 += y1 - ty1;
  x2 += x1 - tx1;

  loop2d_int gy = y2 / h;
  loop2d_int gx = x2 / w;
  y2 %= h;
  x2 %= w;

  V res(0);
  if (gy == 0 && gx == 0) {
    res += range2D<T>(val, y1, x1, y2, x2, h, w);
  } else if (gy == 0) {
    res += range2D<T>(val, y1, x1, y2, w - 1, h, w);
    res += range2D<T>(val, y1, 0, y2, x2, h, w);
    res += range2D<T>(val, y1, 0, y2, w - 1, h, w) * (gx - 1);
  } else if (gx == 0) {
    res += range2D<T>(val, y1, x1, h - 1, x2, h, w);
    res += range2D<T>(val, 0, x1, y2, x2, h, w);
    res += range2D<T>(val, 0, x1, h - 1, x2, h, w) * (gy - 1);
  } else {
    res += range2D<T>(val, y1, x1, h - 1, w - 1, h, w);           // UL
    res += range2D<T>(val, 0, x1, y2, w - 1, h, w);               // DL
    res += range2D<T>(val, y1, 0, h - 1, x2, h, w);               // UR
    res += range2D<T>(val, 0, 0, y2, x2, h, w);                   // DR
    res += range2D<T>(val, y1, 0, h - 1, w - 1, h, w) * (gx - 1); // U
    res += range2D<T>(val, 0, 0, y2, w - 1, h, w) * (gx - 1);     // D
    res += range2D<T>(val, 0, x1, h - 1, w - 1, h, w) * (gy - 1); // L
    res += range2D<T>(val, 0, x1, h - 1, x2, h, w) * (gy - 1);    // R
    res += range2D<T>(val, 0, 0, h - 1, w - 1, h, w) * (gy - 1) * (gx - 1); // C
  }
  return res;
}
// }}}

template <class T, class U> inline void smax(T &a, U b) { a = a > b ? a : b; }
template <class T, class U> inline void smin(T &a, U b) { a = a < b ? a : b; }

int main() {
  std::ios::sync_with_stdio(false), std::cin.tie(0);
  cin >> h >> w;
  vector<vector<int>> f(h, vector<int>(w, 0));
  for (int i = 0; i < h; i++) {
    cin >> s[i];
    for (int j = 0; j < w; j++)
      if (s[i][j] == '.')
        f[i][j] = 1;
  }
  accum2D(f, h, w);

  auto isMonotone = [&](int r1, int c1, int r2, int c2) {
    int x = range2D(f, r1, c1, r2, c2, h, w);
    return x == (r2 - r1 + 1) * (c2 - c1 + 1) || x == 0;
  };

  // i = 0 : 累積和を使っていい感じに求める
  for (int rr = 0; rr < h; rr++)
    for (int r1 = 0; r1 + rr < h; r1++) {
      int r2 = r1 + rr;
      int c1 = 0, c2 = 0;
      for (; c2 < w;) {
        while (c2 < w && isMonotone(r1, c1, r2, c2))
          c2++;
        if (c1 == c2) {
          dp[0][r1][c1][r2] = c2 - 1;
          c1++, c2++;
        } else {
          for (; c1 < c2; c1++) {
            dp[0][r1][c1][r2] = c2 - 1;
          }
        }
      }
    }
  for (int cc = 0; cc < w; cc++)
    for (int c1 = 0; c1 + cc < w; c1++) {
      int c2 = c1 + cc;
      int r1 = 0, r2 = 0;
      for (; r2 < h;) {
        while (r2 < h && isMonotone(r1, c1, r2, c2))
          r2++;
        if (r1 == r2) {
          dp[1][r1][c1][c2] = r2 - 1;
          r1++, r2++;
        } else {
          for (; r1 < r2; r1++) {
            dp[1][r1][c1][c2] = r2 - 1;
          }
        }
      }
    }

  int i = 0;
  while (dp[0][0][0][h - 1] < w - 1) {
    assert(i < C - 1);
    i++;
    // for(int r1 = 0; r1 < h; r1++) for(int c1 = 0; c1 < w; c1++) {
    //   for(int r2 = r1; r2 < h; r2++) dp[0][r1][c1][r2][i] =
    //   dp[0][r1][c1][r2][i-1], dump(i, r1, c1, r2, dp[0][r1][c1][r2][i-1]);
    //   for(int c2 = c1; c2 < w; c2++) dp[1][r1][c1][c2][i] =
    //   dp[1][r1][c1][c2][i-1], dump(i, r1, c1, c2, dp[1][r1][c1][c2][i-1]);
    // }
    for (int r1 = 0; r1 < h; r1++)
      for (int c1 = 0; c1 < w; c1++) {
        // 伸ばしたい方向と垂直に切る場合
        for (int r2 = r1; r2 < h; r2++) {
          // int &d = dp[0][r1][c1][r2][i];
          // int c2 = dp[0][r1][c1][r2][i-1] + 1;
          // if(c2 == w) d = w - 1;
          // else smax(d, dp[0][r1][c2][r2][i-1]);
          // 次元を一個減らしても矛盾は生じない
          int &d = dp[0][r1][c1][r2];
          int c2 = d + 1;
          if (c2 == w)
            d = w - 1;
          else
            smax(d, dp[0][r1][c2][r2]);
        }
        for (int c2 = c1; c2 < w; c2++) {
          int &d = dp[1][r1][c1][c2];
          int r2 = d + 1;
          if (r2 == h)
            d = h - 1;
          else
            smax(d, dp[1][r2][c1][c2]);
        }
        // 伸ばしたい方向と水平に切る場合
        {
          int c2 = w - 1, r2 = r1;
          for (; c2 >= c1; c2--) {
            for (; r2 < h && r2 <= dp[1][r1][c1][c2]; r2++) {
              smax(dp[0][r1][c1][r2], c2);
            }
          }
        }
        {
          int c2 = c1, r2 = h - 1;
          for (; r2 >= r1; r2--) {
            for (; c2 < w && c2 <= dp[0][r1][c1][r2]; c2++) {
              smax(dp[1][r1][c1][c2], r2);
            }
          }
        }
      }
  }

  cout << i << endl;

  return 0;
}


Fixed submission:
// includes {{{
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <tuple>
#include <vector>
// #include<deque>
// #include<multiset>
#include <cstring>
// #include<bits/stdc++.h>
// }}}
using namespace std;
using ll = long long;

string s[185];
const int C = 16;

int dp[2][185 + 1][185 + 1][185 + 1];
int h, w;

// accum2D range2D range2Dloop {{{
#include <type_traits>
using loop2d_int = long long;
template <class T> void accum2D(T &val, int h, int w) {
  for (int i = 1; i < h; i++)
    for (int j = 0; j < w; j++)
      val[i][j] += val[i - 1][j];
  for (int i = 0; i < h; i++)
    for (int j = 1; j < w; j++)
      val[i][j] += val[i][j - 1];
}

template <class T,
          class V = typename std::remove_reference<decltype(T()[0][0])>::type>
V range2D(T &val, int y1, int x1, int y2, int x2, int h, int w) {
  if (y2 >= h)
    y2 = h - 1;
  if (x2 >= w)
    x2 = w - 1;
  if (y1 > y2 || x1 > x2)
    return static_cast<V>(0);
  V res(val[y2][x2]);
  if (y1 - 1 >= 0)
    res -= val[y1 - 1][x2];
  if (x1 - 1 >= 0)
    res -= val[y2][x1 - 1];
  if (y1 - 1 >= 0 && x1 - 1 >= 0)
    res += val[y1 - 1][x1 - 1];
  return res;
}

template <class T,
          class V = typename std::remove_reference<decltype(T()[0][0])>::type>
auto range2Dloop(T &val, loop2d_int ty1, loop2d_int tx1, loop2d_int y2,
                 loop2d_int x2, int h, int w) {
  if (ty1 > y2 || tx1 > x2)
    return static_cast<V>(0);

  loop2d_int y1 = ty1 % h;
  if (y1 < 0)
    y1 += h;
  loop2d_int x1 = tx1 % w;
  if (x1 < 0)
    x1 += w;

  y2 += y1 - ty1;
  x2 += x1 - tx1;

  loop2d_int gy = y2 / h;
  loop2d_int gx = x2 / w;
  y2 %= h;
  x2 %= w;

  V res(0);
  if (gy == 0 && gx == 0) {
    res += range2D<T>(val, y1, x1, y2, x2, h, w);
  } else if (gy == 0) {
    res += range2D<T>(val, y1, x1, y2, w - 1, h, w);
    res += range2D<T>(val, y1, 0, y2, x2, h, w);
    res += range2D<T>(val, y1, 0, y2, w - 1, h, w) * (gx - 1);
  } else if (gx == 0) {
    res += range2D<T>(val, y1, x1, h - 1, x2, h, w);
    res += range2D<T>(val, 0, x1, y2, x2, h, w);
    res += range2D<T>(val, 0, x1, h - 1, x2, h, w) * (gy - 1);
  } else {
    res += range2D<T>(val, y1, x1, h - 1, w - 1, h, w);           // UL
    res += range2D<T>(val, 0, x1, y2, w - 1, h, w);               // DL
    res += range2D<T>(val, y1, 0, h - 1, x2, h, w);               // UR
    res += range2D<T>(val, 0, 0, y2, x2, h, w);                   // DR
    res += range2D<T>(val, y1, 0, h - 1, w - 1, h, w) * (gx - 1); // U
    res += range2D<T>(val, 0, 0, y2, w - 1, h, w) * (gx - 1);     // D
    res += range2D<T>(val, 0, x1, h - 1, w - 1, h, w) * (gy - 1); // L
    res += range2D<T>(val, 0, x1, h - 1, x2, h, w) * (gy - 1);    // R
    res += range2D<T>(val, 0, 0, h - 1, w - 1, h, w) * (gy - 1) * (gx - 1); // C
  }
  return res;
}
// }}}

template <class T, class U> inline void smax(T &a, U b) { a = a > b ? a : b; }
template <class T, class U> inline void smin(T &a, U b) { a = a < b ? a : b; }

int main() {
  std::ios::sync_with_stdio(false), std::cin.tie(0);
  cin >> h >> w;
  vector<vector<int>> f(h, vector<int>(w, 0));
  for (int i = 0; i < h; i++) {
    cin >> s[i];
    for (int j = 0; j < w; j++)
      if (s[i][j] == '.')
        f[i][j] = 1;
  }
  accum2D(f, h, w);

  auto isMonotone = [&](int r1, int c1, int r2, int c2) {
    int x = range2D(f, r1, c1, r2, c2, h, w);
    return x == (r2 - r1 + 1) * (c2 - c1 + 1) || x == 0;
  };

  // i = 0 : 累積和を使っていい感じに求める
  for (int rr = 0; rr < h; rr++)
    for (int r1 = 0; r1 + rr < h; r1++) {
      int r2 = r1 + rr;
      int c1 = 0, c2 = 0;
      for (; c2 < w;) {
        while (c2 < w && isMonotone(r1, c1, r2, c2))
          c2++;
        if (c1 == c2) {
          dp[0][r1][c1][r2] = c2 - 1;
          c1++, c2++;
        } else {
          for (; c1 < c2; c1++) {
            dp[0][r1][c1][r2] = c2 - 1;
          }
        }
      }
    }
  for (int cc = 0; cc < w; cc++)
    for (int c1 = 0; c1 + cc < w; c1++) {
      int c2 = c1 + cc;
      int r1 = 0, r2 = 0;
      for (; r2 < h;) {
        while (r2 < h && isMonotone(r1, c1, r2, c2))
          r2++;
        if (r1 == r2) {
          dp[1][r1][c1][c2] = r2 - 1;
          r1++, r2++;
        } else {
          for (; r1 < r2; r1++) {
            dp[1][r1][c1][c2] = r2 - 1;
          }
        }
      }
    }

  int i = 0;
  while (dp[0][0][0][h - 1] < w - 1) {
    assert(i < C);
    i++;
    // for(int r1 = 0; r1 < h; r1++) for(int c1 = 0; c1 < w; c1++) {
    //   for(int r2 = r1; r2 < h; r2++) dp[0][r1][c1][r2][i] =
    //   dp[0][r1][c1][r2][i-1], dump(i, r1, c1, r2, dp[0][r1][c1][r2][i-1]);
    //   for(int c2 = c1; c2 < w; c2++) dp[1][r1][c1][c2][i] =
    //   dp[1][r1][c1][c2][i-1], dump(i, r1, c1, c2, dp[1][r1][c1][c2][i-1]);
    // }
    for (int r1 = 0; r1 < h; r1++)
      for (int c1 = 0; c1 < w; c1++) {
        // 伸ばしたい方向と垂直に切る場合
        for (int r2 = r1; r2 < h; r2++) {
          // int &d = dp[0][r1][c1][r2][i];
          // int c2 = dp[0][r1][c1][r2][i-1] + 1;
          // if(c2 == w) d = w - 1;
          // else smax(d, dp[0][r1][c2][r2][i-1]);
          // 次元を一個減らしても矛盾は生じない
          int &d = dp[0][r1][c1][r2];
          int c2 = d + 1;
          if (c2 == w)
            d = w - 1;
          else
            smax(d, dp[0][r1][c2][r2]);
        }
        for (int c2 = c1; c2 < w; c2++) {
          int &d = dp[1][r1][c1][c2];
          int r2 = d + 1;
          if (r2 == h)
            d = h - 1;
          else
            smax(d, dp[1][r2][c1][c2]);
        }
        // 伸ばしたい方向と水平に切る場合
        {
          int c2 = w - 1, r2 = r1;
          for (; c2 >= c1; c2--) {
            for (; r2 < h && r2 <= dp[1][r1][c1][c2]; r2++) {
              smax(dp[0][r1][c1][r2], c2);
            }
          }
        }
        {
          int c2 = c1, r2 = h - 1;
          for (; r2 >= r1; r2--) {
            for (; c2 < w && c2 <= dp[0][r1][c1][r2]; c2++) {
              smax(dp[1][r1][c1][c2], r2);
            }
          }
        }
      }
  }

  cout << i << endl;

  return 0;
}