Official

E - Kite Editorial by en_translator


First of all, persons \(i\) and \(j\) \((i \neq j)\) can fly kites simultaneously if and only if:

  • One of the following holds: \(\cdots (\ast)\)
    • \(A_i \lt A_j\) and \(B_i \lt B_j\).
    • \(A_j \lt A_i\) and \(B_j \lt B_i\).

Thus, the problem is reduced to finding the maximum size of a subset \(S\) of \(\lbrace 1,2,\dots, N \rbrace\), where any pair of distinct elements \(i\) and \(j\) of \(S\) satisfy \((\ast)\).

This is boiled down to finding a LIS (Longest Increasing Subsequence).
A LIS is a monotonically increasing subsequence with the maximum length. That is, a LIS of a sequence \(C=(c_1,c_2,\dots,c_N)\) is a subset \(S\) of \(\lbrace 1,2,\dots, N \rbrace\) with the maximum size, such that any pair of distinct elements of \(i\) and \(j\) of \(S\) satisfy:

  • One of the following holds:
    • \(i \lt j\) and \(c_i \lt c_j\)
    • \(j \lt i\) and \(c_j \lt c_i\)

As this condition is similar to \((\ast)\), they seem equivalent by corresponding \(A_i\) to \(i\) and \(B_i\) to \(c_i\). In other words, it appears that the answer to the original problem is the length of a LIS of a sequence that is obtained by sorting the sequence of \((A_i, B_i)\) in ascending order of \(A\) and extracting \(B\).
However, you need to be careful of tie-breaking of \(A_i\). For example, if \((A_1, B_1)=(1,2)\) and \((A_2,B_2)=(1,3)\), we cannot choose \(S =\lbrace 1,2 \rbrace\), but the above LIS-representation of the problem allows to choose that way. The solution is simple; we adopt the following trick:

  • Sort the sequence of \((A_i, B_i)\) in ascending order of \(A_i\). If the values of \(A\) coincide, sort them in descending order of \(B_i\).

One can assert that this trick resolves the issue on tie-breaking. Thus, the problem has been successfully boiled down to a LIS problem.

We omit the explanation on how to find a LIS as we can find several articles regarding the algorithm on the Internet. In fact, a dynamic programming (DP) allows to find the length of a LIS in \(\mathrm{O}(N \log N)\) time, which is fast enough.

  • Sample code (C++)
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
using namespace std;

int main() {
  cin.tie(0)->sync_with_stdio(0);
  int N;
  cin >> N;
  vector<pair<int, int>> AB(N);
  for (auto& [a, b] : AB) cin >> a >> b;
  sort(begin(AB), end(AB), [&](auto& l, auto& r) {
    if (l.first == r.first) return l.second > r.second;
    return l.first < r.first;
  });
  vector<int> dp;
  for (auto& [_, b] : AB) {
    int i = lower_bound(begin(dp), end(dp), b) - begin(dp);
    if (i == (int)dp.size()) {
      dp.push_back(b);
    } else {
      dp[i] = b;
    }
  }
  cout << dp.size() << "\n";
}

posted:
last update: