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

#include <algorithm>
#include <map>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
typedef long long Int;
#define MOD (1000000007)
inline void up(int &a, int b) { a = (a + b) % MOD; }

template <class W> struct E {
  int u, v;
  W w;
  E() {}
  E(int u, int v, const W &w) : u(u), v(v), w(w) {}
};
template <class W> bool less_u(const E<W> &l, const E<W> &r) {
  return l.u != r.u ? l.u < r.u : l.v != r.v ? l.v < r.v : l.w < r.w;
}

int N[2], M[2];
int of(int x, int y, int i, int j) {
  return (((x * 600) + y) * 16 + i) * 16 + j;
}

int main() {
  int T;
  scanf("%d", &T);
  vector<E<string>> g[2];
  map<int, int> dp;
  while (T--) {
    vector<vector<int>> to[2];
    rep(k, 2) {
      scanf("%d%d", N + k, M + k);
      g[k].clear();
      rep(i, M[k]) {
        int a, b;
        char buf[8];
        scanf("%d%d%s", &a, &b, buf);
        g[k].push_back(E<string>(a, b, buf));
      }
      sort(g[k].begin(), g[k].end(), less_u<string>);
      to[k] = vector<vector<int>>(N[k]);
      rep(i, M[k]) {
        const int u = g[k][i].u;
        to[k][u].push_back(i);
      }
      to[k][N[k] - 1].push_back(M[k]);
    }
    dp.clear();
    rep(i, to[0][0].size()) rep(j, to[1][0].size()) {
      const int ix = to[0][0][i], jx = to[1][0][j];
      dp[of(ix, jx, 0, 0)] = 1;
    }
    rep(x, M[0]) rep(y, M[1]) {
      const int v0 = g[0][x].v, v1 = g[1][y].v;
      const string &a = g[0][x].w, &b = g[1][y].w;
      rep(i, a.size()) rep(j, b.size()) if (a[i] == b[j]) {
        const int cur = of(x, y, i, j);
        if (dp.count(cur) == 0)
          continue;
        const int val = dp[cur];
        if (i < (int)a.size() - 1 && j < (int)b.size() - 1) {
          up(dp[of(x, y, i + 1, j + 1)], val);
        } else if (i < (int)a.size() - 1) {
          rep(p, to[1][v1].size()) {
            const int ix = to[1][v1][p];
            up(dp[of(x, ix, i + 1, 0)], val);
          }
        } else if (j < (int)b.size() - 1) {
          rep(p, to[0][v0].size()) {
            const int ix = to[0][v0][p];
            up(dp[of(ix, y, 0, j + 1)], val);
          }
        } else {
          rep(p, to[0][v0].size()) rep(q, to[1][v1].size()) {
            const int ix = to[0][v0][p];
            const int jx = to[1][v1][q];
            up(dp[of(ix, jx, 0, 0)], val);
          }
        }
      }
    }
    printf("%d\\n", dp[of(M[0], M[1], 0, 0)]);
  }
  return 0;
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
typedef long long Int;
#define MOD (1000000007)
inline void up(int &a, int b) { a = (a + b) % MOD; }

template <class W> struct E {
  int u, v;
  W w;
  E() {}
  E(int u, int v, const W &w) : u(u), v(v), w(w) {}
};
template <class W> bool less_u(const E<W> &l, const E<W> &r) {
  return l.u != r.u ? l.u < r.u : l.v != r.v ? l.v < r.v : l.w < r.w;
}

int dp[601][601][5][5];

int main() {
  int T;
  scanf("%d", &T);
  int N[2], M[2];
  vector<E<string>> g[2];
  while (T--) {
    vector<vector<int>> to[2];
    rep(k, 2) {
      scanf("%d%d", N + k, M + k);
      g[k].clear();
      rep(i, M[k]) {
        int a, b;
        char buf[8];
        scanf("%d%d%s", &a, &b, buf);
        g[k].push_back(E<string>(a, b, buf));
      }
      sort(g[k].begin(), g[k].end(), less_u<string>);
      to[k] = vector<vector<int>>(N[k]);
      rep(i, M[k]) {
        const int u = g[k][i].u;
        to[k][u].push_back(i);
      }
      to[k][N[k] - 1].push_back(M[k]);
    }
    memset(dp, 0, sizeof(dp));
    rep(i, to[0][0].size()) rep(j, to[1][0].size()) {
      const int ix = to[0][0][i], jx = to[1][0][j];
      dp[ix][jx][0][0] = 1;
    }
    rep(x, M[0]) rep(y, M[1]) {
      const int v0 = g[0][x].v, v1 = g[1][y].v;
      const string &a = g[0][x].w, &b = g[1][y].w;
      rep(i, a.size()) rep(j, b.size()) if (dp[x][y][i][j] && a[i] == b[j]) {
        if (i < (int)a.size() - 1 && j < (int)b.size() - 1) {
          up(dp[x][y][i + 1][j + 1], dp[x][y][i][j]);
        } else if (i < (int)a.size() - 1) {
          rep(p, to[1][v1].size()) {
            const int ix = to[1][v1][p];
            up(dp[x][ix][i + 1][0], dp[x][y][i][j]);
          }
        } else if (j < (int)b.size() - 1) {
          rep(p, to[0][v0].size()) {
            const int ix = to[0][v0][p];
            up(dp[ix][y][0][j + 1], dp[x][y][i][j]);
          }
        } else {
          rep(p, to[0][v0].size()) rep(q, to[1][v1].size()) {
            const int ix = to[0][v0][p];
            const int jx = to[1][v1][q];
            up(dp[ix][jx][0][0], dp[x][y][i][j]);
          }
        }
      }
    }
    printf("%d\\n", dp[M[0]][M[1]][0][0]);
  }
  return 0;
}