Problem p02604 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

template <typename T1, typename T2> inline void chmin(T1 &a, T2 b) {
  if (a > b)
    a = b;
}
template <typename T1, typename T2> inline void chmax(T1 &a, T2 b) {
  if (a < b)
    a = b;
}

#define REP(i, n) for (int i = 0; i < n; ++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 1
#define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define DBG(fmt, ...)
#endif

const ll LLINF = (1LL << 60);
const int INF = (1LL << 30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
const int MAX_N = 15;

int N;
vector<tuple<int, int, int>> XYP;

// すでにある先のパターンが i のとき Aj に一番近い線までの距離
int near_x[40000][MAX_N];
int near_y[40000][MAX_N];

// 集落ind に一番近い路線との距離を返す
// l_x の i bit 目が立っている　… Xi に線がある
static inline int near(int l_x, int l_y, int ind) {
  return min(near_x[l_x][ind], near_y[l_y][ind]);
}

// 現状の線での値
// l_x の i bit 目が立っている　… Xi に線がある
static inline int calc(int l_x, int l_y) {
  int ret = 0;
  REP(i, N) {
    int p = get<2>(XYP[i]);
    // 自分に一番近い線路を探す
    ret += near(l_x, l_y, i) * p;
  }
  return ret;
}

// i 番目を見ていて cur 本引いている
static inline int dfs(int i, int cur, int n, int l_x, int l_y) {
  if (i >= N) {
    if (n != cur) {
      return LLINF;
    }
    return calc(l_x, l_y);
  }
  int ret = LLINF;

  // 追加しない
  chmin(ret, dfs(i + 1, cur, n, l_x, l_y));

  // x に追加
  if (((l_x >> i) & 1) == 0) {
    chmin(ret, dfs(i + 1, cur + 1, n, l_x | (1 << i), l_y));
  }

  // y に追加
  if (((l_y >> i) & 1) == 0) {
    chmin(ret, dfs(i + 1, cur + 1, n, l_x, l_y | (1 << i)));
  }

  return ret;
}

// 引ける線の数が n のときの最小
static inline int solve(int n) {
  if (n == 0) {
    return calc(0, 0);
  }

  return dfs(0, 0, n, 0, 0);
}

signed main() {
  cin.tie(0);
  cout.tie(0);
  ios::sync_with_stdio(false);

  cin >> N;
  REP(i, N) {
    int x, y, p;
    cin >> x >> y >> p;
    XYP.push_back(make_tuple(x, y, p));
  }

  // near_x, near_y の作成
  for (int i = 0; i < (1 << N); ++i) {
    for (int j = 0; j < N; ++j) {
      near_x[i][j] = abs(get<0>(XYP[j]));
      near_y[i][j] = abs(get<1>(XYP[j]));
      for (int k = 0; k < N; ++k) {
        if ((i >> k) & 1) {
          int dist = abs(get<0>(XYP[k]) - get<0>(XYP[j]));
          chmin(near_x[i][j], dist);
          dist = abs(get<1>(XYP[k]) - get<1>(XYP[j]));
          chmin(near_y[i][j], dist);
        }
      }
    }
  }

  for (int i = 0; i <= N; ++i) {
    int ans = solve(i);
    printf("%lld\\n", ans);
  }

  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

template <typename T1, typename T2> inline void chmin(T1 &a, T2 b) {
  if (a > b)
    a = b;
}
template <typename T1, typename T2> inline void chmax(T1 &a, T2 b) {
  if (a < b)
    a = b;
}

#define REP(i, n) for (int i = 0; i < n; ++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 1
#define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define DBG(fmt, ...)
#endif

const ll LLINF = (1LL << 60);
const int INF = (1LL << 30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
const int MAX_N = 100010;

int N;
vector<tuple<int, int, int>> PXY;

// 自分に一番近い路線との距離を返す
int near(vector<int> &l, int pos) {
  int ret = LLINF;
  for (auto val : l) {
    chmin(ret, abs(val - pos));
  }
  return ret;
}

// 現状の線での値
int calc(vector<int> &l_x, vector<int> &l_y) {
  int ret = 0;
  REP(i, N) {
    int p = get<0>(PXY[i]);
    int x = get<1>(PXY[i]);
    int y = get<2>(PXY[i]);
    // 自分に一番近い線路を探す
    int dist = min(near(l_x, x), near(l_y, y));
    ret += dist * p;
  }
  return ret;
}

// i 番目を見ていて cur 本引いている
int dfs(int i, int cur, int n, vector<int> l_x, vector<int> l_y) {
  if (cur >= n || i >= N) {
    if (n != cur) {
      return LLINF;
    }
    return calc(l_x, l_y);
  }
  int ret = LLINF;
  vector<int> l_x2, l_y2;
  copy(l_x.begin(), l_x.end(), back_inserter(l_x2));
  copy(l_y.begin(), l_y.end(), back_inserter(l_y2));
  int x = get<1>(PXY[i]);
  int y = get<2>(PXY[i]);
#if 1
  chmin(ret, dfs(i + 1, cur, n, l_x, l_y));
  l_x2.push_back(x);
  chmin(ret, dfs(i + 1, cur + 1, n, l_x2, l_y));
  l_y2.push_back(y);
  chmin(ret, dfs(i + 1, cur + 1, n, l_x, l_y2));
#else
  // x に入れるパターン
  auto it = find(l_x.begin(), l_x.end(), x);
  if (it != l_x.end()) {
    chmin(ret, dfs(i + 1, cur, n, l_x2, l_y));
  } else {
    l_x2.push_back(x);
    chmin(ret, dfs(i + 1, cur + 1, n, l_x2, l_y));
  }
  // y に入れるパターン
  it = find(l_y.begin(), l_y.end(), y);
  if (it != l_y.end()) {
    chmin(ret, dfs(i + 1, cur, n, l_x, l_y2));
  } else {
    l_y2.push_back(y);
    chmin(ret, dfs(i + 1, cur + 1, n, l_x, l_y2));
  }
#endif
  return ret;
}

// 引ける線の数が n のときの最小
int solve(int n) {
  vector<int> l_x, l_y;
  l_x.push_back(0);
  l_y.push_back(0);

  if (n == 0) {
    return calc(l_x, l_y);
  }

  // p がでかいやつから試す
  int ret = dfs(0, 0, n, l_x, l_y);

  return ret;
}

signed main() {
  cin.tie(0);
  cout.tie(0);
  ios::sync_with_stdio(false);

  cin >> N;
  REP(i, N) {
    int x, y, p;
    cin >> x >> y >> p;
    PXY.push_back(make_tuple(p, x, y));
  }
  SORT(PXY);
  reverse(PXY.begin(), PXY.end());

  for (int i = 0; i <= N; ++i) {
    int ans = solve(i);
    printf("%lld\\n", ans);
  }

  return 0;
}