競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 225E問題

\(\def \set #1#2{\{ #1 \ \vert \ #2 \}}\)

ABC225E

解法

問題文を翻訳すれば,区間スケジューリング問題と同じ. 区間の両端を,直線の傾きと考えればよい. 整数のペアとして,傾きを有理数で扱うと比較も整数でできる.

注意

分母が0になる場合と,既約でない分数の扱い. \(a \neq 0\) のとき,

  • \(a/0\) を含む類の代表元は \(1/0\) とする.
  • \(0/a\) を含む類の代表元は \(0/1\) とする.
  • \(b/a\) を含む類の代表元は,\(b/a\) を約分した値とする.

今回は出てこないが,負の分数は分子にマイナスを付ける. 理由は,\(y/x < w/z\) の判定が \(yz < wx\) と出来るから. もし分母にマイナスをつけてしまうと,分母を払うときに符号が逆転して面倒.
\(0/0\) は今回は出てこない.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

struct D{
  ll x,y; // y/x
  D(){}
  D(ll x, ll y): x(x), y(y){
    if(x < 0) { x *= -1; y *= -1; }

    if(x == 0 && y == 0) {}
    else if(x == 0) { y = 1; }
    else if(y == 0) { x = 1; }

    // ll d = GCD(x,y);
    // x /= d, y /= d;
  }

  bool compare (D a, auto op) const {
    return op(y*a.x, x*a.y);
  }

  bool operator < (D a) const {
    // y/x < a.y/a.x
    // return y*a.x < x*a.y;
    return compare(a, [&](ll s, ll t) { return s < t; } );
  }


  bool operator == (D a) const {
    // return y*a.x == x*a.y;
    return compare(a, [&](ll s, ll t) { return s == t; } );
  }

};

int main() {
  ll n;
  cin >> n;

  vector<pair<D,D>> p(n);
  rep(i,n){
    ll x,y; cin >> x >> y;
    D l = D(x,y-1);
    D r = D(x-1,y);
    p[i] = {r,l};
  }
  sort(all(p));

  D last = D(1,-1);
  ll ans = 0;
  for(auto [r,l]: p) if(last < l || last == l){
    ans++;
    last = r;
  }
  cout << ans << endl;

  return 0;
}