公式

G - Points and Comparison 解説 by en_translator


Let us assume that \(x\) and \(y\) axes point right and up, respectively. (It is same as the ordinary \(xy\) plane.)
Then, the problem can be rephrased as follows.

  • Given \(N\) points on the \(xy\) plane, find the sum of the answers over the following \(Q\) questions.
    • Given a line on the \(xy\) plane, count the points on or above it.

For each question, it is sufficient to check if \(Y \ge A \times X + B\) for all points, so it is desirable that the points are sorted by \(- A \times X + Y\) (let us call it sort S). How can we achieve it?

First, consider sorting the given lines in ascending order of \(A\).

We need to start from \(A = -\infty\), which is simply achieved by sorting \((X,Y)\) in lexicographical order.

Consider the order of two points \((X_l,Y_l)\) and \((X_r,Y_r)\) in the sort S.

  • If \(X_l = X_r\), the order always satisfies \(Y_l < Y_r\) (the order of these points never changes).
  • Otherwise, their order on the sort S flips when the slope exceeds that of the line passing through the two lines.

Therefore, the following solution is valid:

  • We maintain the sequence of points so that sort S is satisfied.
  • For any two points adjacent in the sequence, if the order will flip as the slope increases, store the slope at which they do in a priority queue.
  • Then, actually process the queries. Refer to the priority queue before processing each query. If there are two points that should be swapped, actually swap them, until there is no such pair.
  • Handle each query with binary search.

Hence, the problem can be solved in a total of \(O(Q (\log Q + \log N) + N^2 \log N)\) time.

This evaluates to \(6.6 \times 10^8\), but the execution time limit is 10 seconds, so you can get AC (accepted) as long as the constant factor is not very bad.

Sample code (C++):

#include<bits/stdc++.h>

using namespace std;
using pl=pair<long long,long long>;
using ppl=pair<pl,long long>;

long long g;
long long md=((1ll<<31)-1);
long long gen(){
  g = (48271*g) % md;
  return g;
}

long long comp_pl(pl a,pl b){
  long long l=a.first*b.second;
  long long r=a.second*b.first;
  if(l<r){return -1;}
  if(l>r){return 1;}
  return 0;
}

int main(){
  long long n;
  cin >> n;
  vector<pl> p(n);
  for(long long i=0;i<n;i++){
    cin >> p[i].first >> p[i].second;
  }
  sort(p.begin(),p.end());

  priority_queue<ppl,vector<ppl>,decltype(
    [](ppl a,ppl b){
      long long cp=comp_pl(a.first,b.first);
      if(cp==0){return (a.second>b.second);}
      if(cp==-1){return false;}
      return true;
    }
  )> pq;

  for(long long i=1;i<n;i++){
    if(p[i-1].first<p[i].first){
      ppl x;
      x.first={p[i].second-p[i-1].second,p[i].first-p[i-1].first};
      x.second=i;
      pq.push(x);
    }
  }

  long long q,ra,rb;
  cin >> q >> g >> ra >> rb;

  vector<pl> ask;
  for(long long i=0;i<q;i++){
    long long g1=gen();
    long long g2=gen();
    long long g3=gen();

    long long a = -ra + (g1%(2*ra+1));
    long long b = -rb + ((g2*md+g3)%(2*rb+1));
    ask.push_back({a,b});
  }

  sort(ask.begin(),ask.end());

  long long res=0;
  for(long long ak=0;ak<q;ak++){
    long long a=ask[ak].first;
    long long b=ask[ak].second;
    while(!pq.empty()){
      ppl od=pq.top();
      long long i=od.second;
      if(
        od.first!=make_pair(p[i].second-p[i-1].second,p[i].first-p[i-1].first)
      ){pq.pop();continue;}

      pl cp=od.first;
      pl cd={a,1};
      if(comp_pl(cp,cd)!=-1){break;}

      pq.pop();
      swap(p[i-1],p[i]);
      i--;
      if(i>0 && p[i-1].first<p[i].first){
        ppl x;
        x.first={p[i].second-p[i-1].second,p[i].first-p[i-1].first};
        x.second=i;
        pq.push(x);
      }
      i+=2;
      if(i<n && p[i-1].first<p[i].first){
        ppl x;
        x.first={p[i].second-p[i-1].second,p[i].first-p[i-1].first};
        x.second=i;
        pq.push(x);
      }
    }

    long long l=0,r=n-1;
    while(l<=r){
      long long te=(l+r)/2;
      if(p[te].second >= a*p[te].first+b){r=te-1;}
      else{l=te+1;}
    }

    res+=(n-1-r);
  }

  cout << res << "\n";
  return 0;
}

投稿日時:
最終更新: