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

#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <vector>

#define X first
#define Y second
#define MAX 1003
using namespace std;

struct state {
  state() : num(0), max(-1), mindex(0) {}
  int num;
  int max;
  int mindex;
};

state dp[MAX][MAX];
bool sosuu[1000001];
map<int, pair<int, int>> pos;
int dx[] = {0, -1, 0, 1};
int dy[] = {-1, 0, 1, 0};
int ddx[] = {-1, 0, 1};

// 素数判定用
void era() {
  fill(sosuu, sosuu + 1000001, true);
  sosuu[0] = false;
  sosuu[1] = false;
  for (int i = 2; i <= 1000000; i++) {
    if (sosuu[i]) {
      for (int j = 2 * i; j <= 1000000; j += i)
        sosuu[j] = false;
    }
  }
}

// 螺旋状に数字を配置する
void fillNum() {
  int rect = 3, count = 1;
  int x = MAX / 2, y = MAX / 2;
  pos[count] = pair<int, int>(x, y);
  dp[y][x].num = count++;
  while (count <= MAX * MAX - 1) {
    pos[count] = pair<int, int>(++x, y);
    dp[y][x].num = count++;
    for (int i = 0; i < 4; i++) {
      for (int j = (i == 0) ? 1 : 0; j < rect - 1; j++) {
        x += dx[i];
        y += dy[i];
        pos[count] = pair<int, int>(x, y);
        dp[y][x].num = count++;
      }
    }
    rect += 2;
  }
}

// 洞穴数は毎回変わるので、入力時にその範囲だけ初期化
void Init(int n) {
  for (int i = 0; i < MAX; i++) {
    for (int j = 0; j < MAX; j++) {
      if (n >= dp[i][j].num) {
        dp[i][j].max = -1;
        dp[i][j].mindex = 0;
      }
    }
  }
}

// メモ化再帰
// スタートからした三方向に対して再帰回して
// 戻ってきたらそこまでの素数洞穴の和を各洞穴に記録していく
int dfs(int x, int y, int n) {
  if (dp[y][x].max >= 0)
    return dp[y][x].max;
  int add = 0;
  for (int i = 0; i < 3; i++) {
    if (dp[y + 1][x + ddx[i]].num > n)
      continue; // 範囲外の洞穴にアクセスしようとしたら止める
    // 三方向に対して再帰を行って、もっとも素数洞穴数が多い場所を採用
    // その際、同じ数が複数あった場合はその中で一番大きい素数洞穴を踏んだ経路を採用
    int tmp = dfs(x + ddx[i], y + 1, n);
    if (add < tmp) {
      add = tmp;
      dp[y][x].mindex = dp[y + 1][x + ddx[i]].mindex;
    } else if (add == tmp) {
      dp[y][x].mindex = dp[y][x].mindex < dp[y + 1][x + ddx[i]].mindex
                            ? dp[y + 1][x + ddx[i]].mindex
                            : dp[y][x].mindex;
    }
  }
  // 自分が素数だった場合1加算する
  dp[y][x].max = sosuu[dp[y][x].num] ? add + 1 : add;
  // 自分が初めての素数洞穴だった場合
  if (!dp[y][x].mindex && sosuu[dp[y][x].num])
    dp[y][x].mindex = dp[y][x].num;
  return dp[y][x].max;
}

int main() {
  era();
  fillNum();
  int n, m;
  while (cin >> n >> m && (n != 0 || m != 0)) {
    Init(n);
    int x = pos[m].X, y = pos[m].Y;
    dfs(x, y, n);
    if (dp[y][x].max == 0)
      cout << 0 << " " << 0 << endl;
    else
      cout << dp[y][x].max << " " << dp[y][x].mindex << endl;
  }
  return 0;
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <vector>

#define X first
#define Y second
#define MAX 1333
using namespace std;

struct state {
  state() : num(0), max(-1), mindex(0) {}
  int num;
  int max;
  int mindex;
};

state dp[MAX][MAX];
bool sosuu[1000001];
map<int, pair<int, int>> pos;
int dx[] = {0, -1, 0, 1};
int dy[] = {-1, 0, 1, 0};
int ddx[] = {-1, 0, 1};

void era() {
  fill(sosuu, sosuu + 1000001, true);
  for (int i = 2; i <= 1000000; i++) {
    if (sosuu[i]) {
      for (int j = 2 * i; j <= 1000000; j += i)
        sosuu[j] = false;
    }
  }
}

void fillNum() {
  int rect = 3, index = 0, count = 1;
  int x = MAX / 2, y = MAX / 2;
  pos[count] = pair<int, int>(x, y);
  dp[y][x].num = count++;
  while (count <= MAX * MAX - 1) {
    pos[count] = pair<int, int>(++x, y);
    dp[y][x].num = count++;
    for (int i = 0; i < 4; i++) {
      for (int j = (i == 0) ? 1 : 0; j < rect - 1; j++) {
        x += dx[i];
        y += dy[i];
        pos[count] = pair<int, int>(x, y);
        dp[y][x].num = count++;
      }
    }
    rect += 2;
  }
}

void Init(int n) {
  for (int i = 0; i < MAX; i++) {
    for (int j = 0; j < MAX; j++) {
      if (n >= dp[i][j].num) {
        dp[i][j].max = -1;
        dp[i][j].mindex = 0;
      }
    }
  }
}

int dfs(int x, int y, int n) {
  if (dp[y][x].max >= 0)
    return dp[y][x].max;
  int add = 0;
  for (int i = 0; i < 3; i++) {
    if (dp[y + 1][x + ddx[i]].num > n)
      continue;
    int tmp = dfs(x + ddx[i], y + 1, n);
    if (add < tmp) {
      add = tmp;
      dp[y][x].mindex = dp[y + 1][x + ddx[i]].mindex;
    } else if (add == tmp) {
      dp[y][x].mindex = dp[y][x].mindex < dp[y + 1][x + ddx[i]].mindex
                            ? dp[y + 1][x + ddx[i]].mindex
                            : dp[y][x].mindex;
    }
  }
  dp[y][x].max = sosuu[dp[y][x].num] ? add + 1 : add;
  if (!dp[y][x].mindex && sosuu[dp[y][x].num])
    dp[y][x].mindex = dp[y][x].num;
  return dp[y][x].max;
}

int main() {
  era();
  fillNum();
  int n, m;
  while (cin >> n >> m && (n != 0 || m != 0)) {
    Init(n);
    int x = pos[m].X, y = pos[m].Y;
    dfs(x, y, n);
    if (dp[y][x].max == 0)
      cout << 0 << " " << 0 << endl;
    else
      cout << dp[y][x].max << " " << dp[y][x].mindex << endl;
  }
  return 0;
}