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

#include <bits/stdc++.h>
using namespace std;

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a) begin((a)), end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
#define UNIQ(c) (c).erase(unique(ALL((c))), end((c)))

#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define FF first
#define SS second

#define DUMP(x) cout << #x << ":" << (x) << endl
template <class S, class T> istream &operator>>(istream &is, pair<S, T> &p) {
  return is >> p.FF >> p.SS;
}
template <class T> istream &operator>>(istream &is, vector<T> &xs) {
  for (auto &x : xs)
    is >> x;
  return is;
}
template <class S, class T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
  return os << p.FF << " " << p.SS;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &xs) {
  for (unsigned int i = 0; i < xs.size(); ++i)
    os << (i ? " " : "") << xs[i];
  return os;
}
template <class T> void maxi(T &x, T y) {
  if (x < y)
    x = y;
}
template <class T> void mini(T &x, T y) {
  if (x > y)
    x = y;
}

const double EPS = 1e-6;
const double PI = acos(-1.0);
const LL MOD = 1e9 + 7;
const double INF = 1e15;

class Point {
public:
  double x, y;

  Point(double x = 0.0, double y = 0.0) : x(x), y(y) {}

  Point &operator+=(const Point &p) {
    x += p.x;
    y += p.y;
    return *this;
  }
  Point operator+(const Point &p) const {
    Point q = *this;
    return q += p;
  }
  Point &operator-=(const Point &p) {
    x -= p.x;
    y -= p.y;
    return *this;
  }
  Point operator-(const Point &p) const {
    Point q = *this;
    return q -= p;
  }
  Point &operator*=(double a) {
    x *= a;
    y *= a;
    return *this;
  }
  Point operator*(double a) const {
    Point q = *this;
    return q *= a;
  }
  Point &operator/=(double a) {
    x /= a;
    y /= a;
    return *this;
  }
  Point operator/(double a) const {
    Point q = *this;
    return q /= a;
  }

  double abs() const { return sqrt(norm()); }
  double norm() const { return x * x + y * y; }
  Point &normalize() { return *this /= abs(); }

  bool operator<(const Point &p) const { return y != p.y ? y < p.y : x < p.x; }

  // EPSは十分小さな値
  bool operator==(const Point &p) const {
    return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
  }
  friend ostream &operator<<(ostream &os, const Point &p);
};
ostream &operator<<(ostream &os, const Point &p) {
  return os << "(" << p.x << "," << p.y << ")";
}

typedef vector<Point> Polygon;
typedef Point Vector;
// 内積
double dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; }

// 外積の大きさ
double cross(Vector a, Vector b) { return a.x * b.y - a.y * b.x; }

int ccw(Point p0, Point p1, Point p2) {

  // p0->p1をp0始点、p1終点の基準ベクトルとしたとき

  // p0->p2が反時計回りになるとき
  static const int COUNTER_CLOCKWISE = 1;
  // p0->p2が時計回りになるとき
  static const int CLOCKWISE = -1;
  // p2,p0,p1の順で同一直線上にあるとき
  static const int ONLINE_BACK = 2;
  // p0,p1,p2 の順で同一直線上にある場合
  static const int ONLINE_FRONT = -2;
  // p2 が線分 p0p1 上にある場合
  static const int ON_SEGMENT = 0;

  Vector a = p1 - p0;
  Vector b = p2 - p0;

  if (cross(a, b) > EPS)
    return COUNTER_CLOCKWISE;
  if (cross(a, b) < -EPS)
    return CLOCKWISE;
  if (dot(a, b) < -EPS)
    return ONLINE_BACK;
  if (a.norm() < b.norm())
    return ONLINE_FRONT;

  return ON_SEGMENT;
}
Polygon andrewScan(Polygon s) {
  Polygon u, l;

  if (s.size() < 3)
    return s;

  sort(s.begin(), s.end()); // x,yを基準にソート

  u.push_back(s[0]);
  u.push_back(s[1]);

  l.push_back(s[s.size() - 1]);
  l.push_back(s[s.size() - 2]);

  // 凸方の上部を生成
  for (unsigned int i = 2; i < s.size(); i++) {
    for (int n = u.size(); n >= 2 && ccw(u[n - 2], u[n - 1], s[i]) == 1; n--) {
      u.pop_back();
    }
    u.push_back(s[i]);
  }

  // 凸法の下部を生成
  for (int i = s.size() - 3; i >= 0; i--) {
    for (int n = l.size(); n >= 2 && ccw(l[n - 2], l[n - 1], s[i]) == 1; n--) {
      l.pop_back();
    }
    l.push_back(s[i]);
  }

  // 反時計回りになるように凸包の点の列
  reverse(l.begin(), l.end());
  for (int i = u.size() - 2; i >= 1; i--)
    l.push_back(u[i]);

  return l;
}

double tri_area(Point p1, Point p2, Point p3) {
  return abs(cross(p2 - p1, p3 - p1)) / 2.;
}

double dp[41][41][41][41];
int rev[41][41][41][41];

int main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  int N;
  cin >> N;
  vector<pair<Point, int>> ps(N);
  REP(i, N) {
    cin >> ps[i].FF.x >> ps[i].FF.y;
    ps[i].SS = i + 1;
  }
  SORT(ps);

  fill((double *)dp, (double *)dp + 41 * 41 * 41 * 41, INF);
  REP(i1, N) REP(i2, N) REP(i3, N) {
    if (i1 == i2 || i2 == i3 || i1 == i3)
      continue;
    if (ps[i2] < ps[i1] || ps[i3] < ps[i1])
      continue;
    if (ccw(ps[i1].FF, ps[i2].FF, ps[i3].FF) == 1) {
      dp[3][i1][i2][i3] = tri_area(ps[i1].FF, ps[i2].FF, ps[i3].FF);
    }
  }

  FOR(i, 3, N) REP(b, N) REP(j, N) REP(k, N) {
    if (dp[i][b][j][k] >= INF)
      continue;
    FOR(n, b + 1, N) {
      if (n == b || n == j || n == k)
        continue;
      if (ccw(ps[j].FF, ps[k].FF, ps[n].FF) != 1 ||
          ccw(ps[b].FF, ps[n].FF, ps[k].FF) != -1)
        continue;
      double res = dp[i][b][j][k] + tri_area(ps[k].FF, ps[n].FF, ps[b].FF);
      if (res < dp[i + 1][b][k][n]) {
        dp[i + 1][b][k][n] = res;
        rev[i + 1][b][k][n] = j;
      }
    }
  }

  int Q;
  cin >> Q;
  REP(q, Q) {
    int K;
    cin >> K;

    int ab = -1, aj, ak;
    double best = INF;
    REP(b, N) REP(j, N) REP(k, N) {
      if (dp[K][b][j][k] >= INF)
        continue;
      if (dp[K][b][j][k] <= best - EPS) {
        best = dp[K][b][j][k];
        ab = b;
        aj = j;
        ak = k;
      } else if (abs(dp[K][b][j][k] - best) <= EPS) {
        if (ps[b] < ps[ab]) {
          best = dp[K][b][j][k];
          ab = b;
          aj = j;
          ak = k;
        }
      }
    }
    if (ab == -1) {
      cout << "NA" << endl;
      continue;
    }

    VI ans;
    for (int k = K; k > 3; --k) {
      ans.PB(ps[ak].SS);
      int r = rev[k][ab][aj][ak];
      ak = aj;
      aj = r;
    }
    ans.PB(ps[ak].SS);
    ans.PB(ps[aj].SS);
    ans.PB(ps[ab].SS);
    reverse(ALL(ans));
    cout << ans << endl;
  }

  return 0;
}


Error: MLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;

using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using LL = long long;
using VL = vector<LL>;
using VVL = vector<VL>;
using PLL = pair<LL, LL>;
using VS = vector<string>;

#define ALL(a) begin((a)), end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
#define UNIQ(c) (c).erase(unique(ALL((c))), end((c)))

#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define FF first
#define SS second

#define DUMP(x) cout << #x << ":" << (x) << endl
template <class S, class T> istream &operator>>(istream &is, pair<S, T> &p) {
  return is >> p.FF >> p.SS;
}
template <class T> istream &operator>>(istream &is, vector<T> &xs) {
  for (auto &x : xs)
    is >> x;
  return is;
}
template <class S, class T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
  return os << p.FF << " " << p.SS;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &xs) {
  for (unsigned int i = 0; i < xs.size(); ++i)
    os << (i ? " " : "") << xs[i];
  return os;
}
template <class T> void maxi(T &x, T y) {
  if (x < y)
    x = y;
}
template <class T> void mini(T &x, T y) {
  if (x > y)
    x = y;
}

const double EPS = 1e-10;
const double PI = acos(-1.0);
const LL MOD = 1e9 + 7;

class Point {
public:
  double x, y;

  Point(double x = 0.0, double y = 0.0) : x(x), y(y) {}

  Point &operator+=(const Point &p) {
    x += p.x;
    y += p.y;
    return *this;
  }
  Point operator+(const Point &p) const {
    Point q = *this;
    return q += p;
  }
  Point &operator-=(const Point &p) {
    x -= p.x;
    y -= p.y;
    return *this;
  }
  Point operator-(const Point &p) const {
    Point q = *this;
    return q -= p;
  }
  Point &operator*=(double a) {
    x *= a;
    y *= a;
    return *this;
  }
  Point operator*(double a) const {
    Point q = *this;
    return q *= a;
  }
  Point &operator/=(double a) {
    x /= a;
    y /= a;
    return *this;
  }
  Point operator/(double a) const {
    Point q = *this;
    return q /= a;
  }

  double abs() const { return sqrt(norm()); }
  double norm() const { return x * x + y * y; }
  Point &normalize() { return *this /= abs(); }

  bool operator<(const Point &p) const { return y != p.y ? y < p.y : x < p.x; }

  // EPSは十分小さな値
  bool operator==(const Point &p) const {
    return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
  }
  friend ostream &operator<<(ostream &os, const Point &p);
};
ostream &operator<<(ostream &os, const Point &p) {
  return os << "(" << p.x << "," << p.y << ")";
}

class Segment {
public:
  Point p1, p2;
  Segment() {}
  Segment(const Point &p1_, const Point &p2_) : p1(p1_), p2(p2_) {}
};

class Circle {
public:
  Point c;
  double r;
};

typedef vector<Point> Polygon;

// 点を線として扱う
typedef Point Vector;
// 線分を直線として扱う
typedef Segment Line;

// 内積
double dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; }

// 外積の大きさ
double cross(Vector a, Vector b) { return a.x * b.y - a.y * b.x; }

int ccw(Point p0, Point p1, Point p2) {

  // p0->p1をp0始点、p1終点の基準ベクトルとしたとき

  // p0->p2が反時計回りになるとき
  static const int COUNTER_CLOCKWISE = 1;
  // p0->p2が時計回りになるとき
  static const int CLOCKWISE = -1;
  // p2,p0,p1の順で同一直線上にあるとき
  static const int ONLINE_BACK = 2;
  // p0,p1,p2 の順で同一直線上にある場合
  static const int ONLINE_FRONT = -2;
  // p2 が線分 p0p1 上にある場合
  static const int ON_SEGMENT = 0;

  Vector a = p1 - p0;
  Vector b = p2 - p0;

  if (cross(a, b) > EPS)
    return COUNTER_CLOCKWISE;
  if (cross(a, b) < -EPS)
    return CLOCKWISE;
  if (dot(a, b) < -EPS)
    return ONLINE_BACK;
  if (a.norm() < b.norm())
    return ONLINE_FRONT;

  return ON_SEGMENT;
}
Polygon andrewScan(Polygon s) {
  Polygon u, l;

  if (s.size() < 3)
    return s;

  sort(s.begin(), s.end()); // x,yを基準にソート

  u.push_back(s[0]);
  u.push_back(s[1]);

  l.push_back(s[s.size() - 1]);
  l.push_back(s[s.size() - 2]);

  // 凸方の上部を生成
  for (int i = 2; i < s.size(); i++) {
    for (int n = u.size(); n >= 2 && ccw(u[n - 2], u[n - 1], s[i]) == 1; n--) {
      u.pop_back();
    }
    u.push_back(s[i]);
  }

  // 凸法の下部を生成
  for (int i = s.size() - 3; i >= 0; i--) {
    for (int n = l.size(); n >= 2 && ccw(l[n - 2], l[n - 1], s[i]) == 1; n--) {
      l.pop_back();
    }
    l.push_back(s[i]);
  }

  // 反時計回りになるように凸包の点の列
  reverse(l.begin(), l.end());
  for (int i = u.size() - 2; i >= 1; i--)
    l.push_back(u[i]);

  return l;
}

// 多角形の面積を求める //凸包のソート済みが前提
double polygon_area(const Polygon &t) {
  double ans = 0.0;
  for (unsigned int i = 0; i < t.size(); i++)
    ans += cross(t[i], t[(i + 1) % t.size()]);
  return ans / 2;
}

vector<vector<Polygon>> pols(41);
vector<Polygon> ans(41);
VVI ansi(41);

int main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  int N;
  cin >> N;

  Polygon ps(N);
  REP(i, N) cin >> ps[i].x >> ps[i].y;

  REP(i1, N) REP(i2, i1) REP(i3, i2) {
    Polygon p;
    p.push_back(ps[i1]);
    p.push_back(ps[i2]);
    p.push_back(ps[i3]);
    p = andrewScan(p);
    pols[3].EB(p);
  }

  FOR(i, 3, N) {
    if (pols[i].empty())
      break;

    double area = 1e15;
    while (!pols[i].empty()) {
      auto p = pols[i].back();
      pols[i].pop_back();

      double a = polygon_area(p);
      if (a < area) {
        area = a;
        ans[i] = p;
      }

      REP(j, N) {
        p.push_back(ps[j]);
        Polygon tmp = andrewScan(p);
        if (SZ(tmp) == i + 1) {
          pols[i + 1].EB(tmp);
        }
        p.pop_back();
      }
    }
  }

  if (!pols[N].empty()) {
    int i = N;
    int mi = 0;
    double area = polygon_area(pols[i][0]);
    FOR(j, 1, SZ(pols[i])) {
      double a = polygon_area(pols[i][j]);
      if (a < area) {
        mi = j;
        area = a;
      }
    }
    ans[i] = pols[i][mi];
  }

  FOR(i, 3, N + 1) {
    if (ans[i].empty())
      continue;
    for (auto &p : ans[i]) {
      REP(j, N) {
        if (p == ps[j]) {
          ansi[i].PB(j + 1);
          break;
        }
      }
    }
  }

  int Q;
  cin >> Q;
  REP(q, Q) {
    int k;
    cin >> k;
    if (ansi[k].empty())
      cout << "NA" << endl;
    else
      cout << ansi[k] << endl;
  }

  return 0;
}