Problem p01424 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <algorithm>
#include <assert.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <vector>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c)                                                           \
  for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

struct State {
  int lr;
  int left;
  int right;
  int use;
  State() { ; }
  State(int lr, int left, int right, int use)
      : lr(lr), left(left), right(right), use(use) {
    ;
  }
};

int n, m;
char strs[110][20];
int len[110];
vector<int> g[110];
vector<int> revG[110];
ll memo[2][110][110][12];
int palinMemo[2][110][12];
State moveMemo[2][110][110][12];
int visit[2][110][110][12];

int isPalin(const int lr, const int index, const int use) {
  if (palinMemo[lr][index][use] != -1) {
    return palinMemo[lr][index][use];
  }
  int ret = 1;
  int l = 0;
  int r = len[index] - 1;
  if (lr == 0) {
    l += use;
  } else {
    r -= use;
  }
  while (l < r) {
    if (strs[index][l] != strs[index][r]) {
      ret = 0;
    }
    l++;
    r--;
  }
  return palinMemo[lr][index][use] = ret;
}

State Move(const int lr, const int left, const int right, const int use) {
  if (moveMemo[lr][left][right][use].lr != -1) {
    return moveMemo[lr][left][right][use];
  }
  State ret(2, left, right, -1);
  int l = 0;
  int r = len[right] - 1;
  if (lr == 0) {
    l += use;
  } else {
    r -= use;
  }
  while (l < len[left] && r >= 0) {
    if (strs[left][l] != strs[right][r]) {
      goto end;
    }
    l++;
    r--;
  }
  if (r == -1) {
    ret.lr = 0;
    ret.use = l;
  } else {
    ret.lr = 1;
    ret.use = (len[right] - r) - 1;
  }
end:
  return moveMemo[lr][left][right][use] = ret;
}

ll calc(const int lr, const int left, const int right, const int use) {
  if (memo[lr][left][right][use] != -1) {
    return memo[lr][left][right][use];
  }
  // cout << lr << " " << left << " " << right << " " << use << endl;
  if (visit[lr][left][right][use] >= 1) {
    visit[lr][left][right][use] = 2;
    return -(1LL << 60);
  }
  visit[lr][left][right][use] = 1;
  ll ret = -(1LL << 60);
  vector<int> *target = NULL;
  FORIT(it, g[left]) {
    if (*it == right) {
      if ((lr == 0 && isPalin(lr, left, use)) ||
          (lr == 1 && isPalin(lr, right, use))) {
        ret = max(ret, 0LL);
      }
      break;
    }
  }
  if (lr == 0) {
    target = &revG[right];
  } else {
    target = &g[left];
  }
  FORIT(it, *target) {
    if (*it >= n) {
      continue;
    }
    State next;
    if (lr == 0) {
      next = Move(lr, left, *it, use);
    } else {
      next = Move(lr, *it, right, use);
    }
    if (next.use == -1) {
      continue;
    }
    ret = max(ret, calc(next.lr, next.left, next.right, next.use) + len[*it]);
  }
  if (visit[lr][left][right][use] == 2 && ret >= 0) {
    ret = 1LL << 60;
  }
  // cout << "ret:" << lr << " " << left << " " << right << " " << use << " " <<
  // ret << endl;
  visit[lr][left][right][use] = 0;
  return ret;
}

int main() {
  while (scanf("%d %d", &n, &m) > 0) {
    MEMSET(palinMemo, -1);
    MEMSET(memo, -1);
    MEMSET(moveMemo, -1);
    MEMSET(visit, 0);
    REP(i, 110) {
      g[i].clear();
      revG[i].clear();
    }
    REP(i, n) {
      scanf("%s", strs[i]);
      len[i] = strlen(strs[i]);
    }
    REP(i, m) {
      int f, t;
      scanf("%d %d", &f, &t);
      f--;
      t--;
      g[f].push_back(t);
      revG[t].push_back(f);
    }
    len[n] = 0;
    len[n + 1] = 0;
    strs[n][0] = '\0';
    strs[n + 1][0] = '\0';
    REP(i, n) {
      g[n].push_back(i);
      revG[i].push_back(n);
      g[i].push_back(n + 1);
      revG[n + 1].push_back(i);
    }

    ll ans = calc(0, n, n + 1, 0);
    ans = max(ans, 0LL);
    if (ans >= (1LL << 60)) {
      puts("-1");
    } else {
      printf("%lld\n", ans);
    }
  }
}

Fixed submission:
#include <algorithm>
#include <assert.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <vector>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c)                                                           \
  for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

struct State {
  int lr;
  int left;
  int right;
  int use;
  State() { ; }
  State(int lr, int left, int right, int use)
      : lr(lr), left(left), right(right), use(use) {
    ;
  }
};

int n, m;
char strs[110][20];
int len[110];
vector<int> g[110];
vector<int> revG[110];
ll memo[2][110][110][12];
int palinMemo[2][110][12];
State moveMemo[2][110][110][12];
int visit[2][110][110][12];

int isPalin(const int lr, const int index, const int use) {
  if (palinMemo[lr][index][use] != -1) {
    return palinMemo[lr][index][use];
  }
  int ret = 1;
  int l = 0;
  int r = len[index] - 1;
  if (lr == 0) {
    l += use;
  } else {
    r -= use;
  }
  while (l < r) {
    if (strs[index][l] != strs[index][r]) {
      ret = 0;
    }
    l++;
    r--;
  }
  return palinMemo[lr][index][use] = ret;
}

State Move(const int lr, const int left, const int right, const int use) {
  if (moveMemo[lr][left][right][use].lr != -1) {
    return moveMemo[lr][left][right][use];
  }
  State ret(2, left, right, -1);
  int l = 0;
  int r = len[right] - 1;
  if (lr == 0) {
    l += use;
  } else {
    r -= use;
  }
  while (l < len[left] && r >= 0) {
    if (strs[left][l] != strs[right][r]) {
      goto end;
    }
    l++;
    r--;
  }
  if (r == -1) {
    ret.lr = 0;
    ret.use = l;
  } else {
    ret.lr = 1;
    ret.use = (len[right] - r) - 1;
  }
end:
  return moveMemo[lr][left][right][use] = ret;
}

ll calc(const int lr, const int left, const int right, const int use) {
  if (memo[lr][left][right][use] != -1) {
    return memo[lr][left][right][use];
  }
  // cout << lr << " " << left << " " << right << " " << use << endl;
  if (visit[lr][left][right][use] >= 1) {
    visit[lr][left][right][use] = 2;
    return -(1LL << 60);
  }
  visit[lr][left][right][use] = 1;
  ll ret = -(1LL << 60);
  vector<int> *target = NULL;
  FORIT(it, g[left]) {
    if (*it == right) {
      if ((lr == 0 && isPalin(lr, left, use)) ||
          (lr == 1 && isPalin(lr, right, use))) {
        ret = max(ret, 0LL);
      }
      break;
    }
  }
  if (lr == 0) {
    target = &revG[right];
  } else {
    target = &g[left];
  }
  FORIT(it, *target) {
    if (*it >= n) {
      continue;
    }
    State next;
    if (lr == 0) {
      next = Move(lr, left, *it, use);
    } else {
      next = Move(lr, *it, right, use);
    }
    if (next.use == -1) {
      continue;
    }
    ret = max(ret, calc(next.lr, next.left, next.right, next.use) + len[*it]);
  }
  if (visit[lr][left][right][use] == 2 && ret >= 0) {
    ret = 1LL << 60;
  }
  // cout << "ret:" << lr << " " << left << " " << right << " " << use << " " <<
  // ret << endl;
  visit[lr][left][right][use] = 0;
  return memo[lr][left][right][use] = ret;
}

int main() {
  while (scanf("%d %d", &n, &m) > 0) {
    MEMSET(palinMemo, -1);
    MEMSET(memo, -1);
    MEMSET(moveMemo, -1);
    MEMSET(visit, 0);
    REP(i, 110) {
      g[i].clear();
      revG[i].clear();
    }
    REP(i, n) {
      scanf("%s", strs[i]);
      len[i] = strlen(strs[i]);
    }
    REP(i, m) {
      int f, t;
      scanf("%d %d", &f, &t);
      f--;
      t--;
      g[f].push_back(t);
      revG[t].push_back(f);
    }
    len[n] = 0;
    len[n + 1] = 0;
    strs[n][0] = '\0';
    strs[n + 1][0] = '\0';
    REP(i, n) {
      g[n].push_back(i);
      revG[i].push_back(n);
      g[i].push_back(n + 1);
      revG[n + 1].push_back(i);
    }

    ll ans = calc(0, n, n + 1, 0);
    ans = max(ans, 0LL);
    if (ans >= (1LL << 60)) {
      puts("-1");
    } else {
      printf("%lld\n", ans);
    }
  }
}