Submission #529514

#TimeUsernameProblemLanguageResultExecution timeMemory
529514msg555Aliens (IOI16_aliens)C++14
60 / 100
2071 ms12224 KiB
#include "aliens.h"

#include <vector>
#include <algorithm>
#include <iostream>
#include <set>
#include <cassert>

using namespace std;

long long squared(int x) {
  return 1ll * x * x;

}

template<typename T>
struct line_elem {
  T a;
  T b;
  T x_start;
  bool point_query;

  line_elem() : a(0), b(0), x_start(0), point_query(false) {}
  line_elem(T x) : a(0), b(0), x_start(x), point_query(true) {}
  line_elem(T a, T b, T x_start = 0) : a(a), b(b), x_start(x_start), point_query(false) {}

  T get(T x) const {
    return a * x + b;
  }

  bool operator<(const line_elem& rhs) const {
    if (point_query || rhs.point_query) {
      return x_start < rhs.x_start;
    }

    return make_pair(a, b) < make_pair(rhs.a, rhs.b);
  }

  bool operator<(const pair<T, T>& rhs) const {
    return make_pair(a, b) < rhs;
  }

  bool operator<(T x) const {
    return x_start < x;
  }
};

template<typename T>
T cross_x(const line_elem<T>& X, const line_elem<T>& Y) {
  /* Returns the first x >= to when the lines intersect */
  T da = X.a - Y.a;
  T db = Y.b - X.b;
  assert(da != 0);
  if (da < 0) {
    da = -da;
    db = -db;
  }
  if (db < 0) {
    return db / da;
  }
  return (db + da - 1) / da;
}

template<typename T>
struct line_hull {
  
  /* Implements a max hull, get the max ax+b for all inserted lines. */

  bool insert(T a, T b) {
    /* Insert line ax+b */
    auto ln = line_elem<T>(a, b);
    auto it = st.lower_bound(ln);
    bool is_last = it == st.end();
    if (!is_last && ln.a == it->a) {
      return false;
    }

    auto jt = it;
    bool is_first = it == st.begin();
    if (!is_first) {
      --it;  
      if (it->a == ln.a) {
        if (it == st.begin()) {
          is_first = true;
        } else {
          --it;
        }
      }
    }

    T lft_x = is_first ? numeric_limits<T>::min() : cross_x(*it, ln);
    T rht_x = is_last ? numeric_limits<T>::max() : cross_x(ln, *jt);
    if (rht_x <= lft_x) {
      return false;
    }

    if (!is_first) {
      while (it != st.begin()) {
        auto kt = it--;
        T prev_lft_x = cross_x(*it, *kt);
        if (prev_lft_x < lft_x) {
          ++it;
          break;
        }
        lft_x = cross_x(*it, ln);
      }
      ++it;
    }

    if (!is_last) {
      while (true) {
        auto kt = jt++;
        if (jt == st.end()) {
          break;
        }
        
        T prev_rht_x = cross_x(*kt, *jt);
        if (rht_x < prev_rht_x) {
          break;
        }
        rht_x = cross_x(ln, *jt);
      }
      --jt;
    }

    line_elem<T> new_rht;
    if (!is_last) {
      new_rht = *jt++;
    }
    st.erase(it, jt);
    st.insert(line_elem<T>(a, b, lft_x));
    if (!is_last) {
      new_rht.x_start = rht_x;
      st.insert(new_rht);
    }

    return true;
  }

  T get(T x) const {
    auto it = st.upper_bound(x);
    --it;
    return it->get(x);
  }

  set<line_elem<T> > st;
};

const size_t MAXN = 100010;

pair<int, int> A[MAXN];
long long ADJ[MAXN];

long long sample(int N, int K, long long C) {
  line_hull<long long> hl;
  long long val = 0;
  for (int i = 0; i <= N; i++) {
    val = 0;
    if (i) {
      long long x = A[i - 1].first;
      val = -hl.get(x) + squared(x) + C;
    }

    long long sadd = 1 + A[i].second - A[i].first;
    long long b = 2 * sadd;
    long long c = squared(sadd) + val - ADJ[i];
    hl.insert(-b, -c);
  }

  return val - K * C;
}

long long take_photos(int N, int M, int K, vector<int> R, vector<int> C) {
  for (int i = 0; i < N; i++) {
    int ri = R[i];
    int ci = C[i];
    if (ri > ci) swap(ri, ci);
    A[i] = make_pair(ci, ci - ri);
  }
  sort(A, A + N);

  int j = 0;
  for (int i = 0; i < N; i++) {
    while (j > 0 && A[i].second >= A[j - 1].second + A[i].first - A[j - 1].first) {
      --j;
    }
    A[j++] = A[i];
  }
  N = j;
  K = min(K, N);

  for (int i = 1; i < N; i++) {
    ADJ[i] = squared(max(0, 1 + A[i].second - A[i].first + A[i - 1].first));
  }

  long long lo = 0;
  long long hi = 16;
  long long lstv = sample(N, K, hi);
  while (true) {
    long long v = sample(N, K, 2 * hi);
    if (v <= lstv) {
      hi *= 2;
      break;
    }
    lo = hi;
    hi *= 2;
    lstv = v;
  }

  while (lo + 3 <= hi) {
    long long md1 = lo + (hi - lo) / 3;
    long long md2 = lo + 2 * (hi - lo) / 3;
    if (sample(N, K, md1) < sample(N, K, md2)) {
      lo = md1 + 1;
    } else {
      hi = md2;
    }
  }

  long long result = numeric_limits<long long>::min();
  for (long long i = lo; i < hi; i++) {
    result = max(result, sample(N, K, i));
  }
  return result;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...