Problem p00482 (C++) — buggy submission, verdict: Memory Limit Exceeded

#include <algorithm>
#include <bitset>
#include <cassert>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <valarray>
#include <vector>
using namespace std;

#define REP(i, n) for (int i = 0; i < (int)n; ++i)
#define FOR(i, c)                                                              \\
  for (__typeof((c).begin()) i = (c).begin(); i != (c).end(); ++i)
#define ALL(c) (c).begin(), (c).end()
typedef long long ll;
typedef pair<int, int> pii;
const int INF = 1 << 29;
const double PI = acos(-1);
const double EPS = 1e-8;

const int mod = 100000;
void add(int &x, int y) { x = (x + y) % mod; }

int dp[2][1 << 20][2];
char ba[20][20];
int cnt[20][20]; // (i,j)以降に何個?があるか
int pow3[400];

int main() {
  int h, w;
  cin >> h >> w;

  REP(y, h) REP(x, w) { cin >> ba[y][x]; }

  int sum = 0; // ?の累積和
  for (int y = h - 1; y >= 0; --y) {
    for (int x = w - 1; x >= 0; --x) {
      cnt[y][x] = sum;
      if (ba[y][x] == '?') {
        sum += 1;
      }
    }
  }
  // pow3の計算
  pow3[0] = 1;
  REP(i, 400 - 1) pow3[i + 1] = pow3[i] * 3 % mod;

  memset(dp, 0, sizeof(dp));
  dp[0][0][0] = 1;

  int c = 0;
  ll ans = 0;
  REP(y, h) {
    REP(x, w) {
      int d = !c;
      REP(S, 1 << w) REP(i, 2) dp[d][S][i] = 0;
      REP(S, 1 << w) {
        int T = S & ~(1 << x);
        // J
        if (ba[y][x] == 'J' || ba[y][x] == '?') {
          add(dp[d][T][1], dp[c][S][0] + dp[c][S][1]);
        }
        // O
        if (ba[y][x] == 'O' || ba[y][x] == '?') {
          ll tmp = dp[c][S][0];
          if (x) {
            // 左がJならフラグを立てる
            add(dp[d][T | 1 << (x - 1)][0], dp[c][S][1]);
          } else {
            tmp += dp[c][S][1];
          }
          // 左がJで無かったり、左端の場合
          add(dp[d][T][0], tmp);
        }
        // I
        if (ba[y][x] == 'I' || ba[y][x] == '?') {
          int tmp = dp[c][S][0] + dp[c][S][1];
          if (S >> x & 1) { // 上にJOができてる
            ans = (ans + (ll)tmp * pow3[cnt[y][x]]) % mod;
          } else {
            add(dp[d][T][0], tmp);
          }
        }
      }
      c ^= 1;
    }
  }
  cout << ans << endl;
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <bitset>
#include <cassert>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <valarray>
#include <vector>
using namespace std;

#define REP(i, n) for (int i = 0; i < (int)n; ++i)
#define FOR(i, c)                                                              \\
  for (__typeof((c).begin()) i = (c).begin(); i != (c).end(); ++i)
#define ALL(c) (c).begin(), (c).end()
typedef long long ll;
typedef pair<int, int> pii;
const int INF = 1 << 29;
const double PI = acos(-1);
const double EPS = 1e-8;

const int mod = 100000;
void add(ll &x, ll y) { x = (x + y) % mod; }

ll dp[2][1 << 20][2];
char ba[20][20];
int cnt[20][20]; // (i,j)以降に何個?があるか
ll pow3[400];

int main() {
  int h, w;
  cin >> h >> w;

  REP(y, h) REP(x, w) { cin >> ba[y][x]; }

  int sum = 0; // ?の累積和
  for (int y = h - 1; y >= 0; --y) {
    for (int x = w - 1; x >= 0; --x) {
      cnt[y][x] = sum;
      if (ba[y][x] == '?') {
        sum += 1;
      }
    }
  }
  // pow3の計算
  pow3[0] = 1;
  REP(i, 400 - 1) pow3[i + 1] = pow3[i] * 3 % mod;

  memset(dp, 0, sizeof(dp));
  dp[0][0][0] = 1;

  int c = 0;
  ll ans = 0;
  REP(y, h) {
    REP(x, w) {
      int d = !c;
      REP(S, 1 << w) REP(i, 2) dp[d][S][i] = 0;
      REP(S, 1 << w) {
        int T = S & ~(1 << x);
        // J
        if (ba[y][x] == 'J' || ba[y][x] == '?') {
          add(dp[d][T][1], dp[c][S][0] + dp[c][S][1]);
        }
        // O
        if (ba[y][x] == 'O' || ba[y][x] == '?') {
          ll tmp = dp[c][S][0];
          if (x) {
            // 左がJならフラグを立てる
            add(dp[d][T | 1 << (x - 1)][0], dp[c][S][1]);
          } else {
            tmp += dp[c][S][1];
          }
          // 左がJで無かったり、左端の場合
          add(dp[d][T][0], tmp);
        }
        // I
        if (ba[y][x] == 'I' || ba[y][x] == '?') {
          ll tmp = dp[c][S][0] + dp[c][S][1];
          if (S >> x & 1) { // 上にJOができてる
            ans = (ans + tmp * pow3[cnt[y][x]]) % mod;
          } else {
            add(dp[d][T][0], tmp);
          }
        }
      }
      c ^= 1;
    }
  }
  cout << ans << endl;
}