分析

要求我们在一条直线上确定一个点。要求它覆盖的点最多。我们可以转换一下,对于每个点我们可以覆盖到它的地方有哪些。如此我们发现这些地方,一定在直线上构成一个线段,或者没有交点。那么我们就可以求出这个范围,然后通过差分就可以求出最多被覆盖的区间。这个我们可以通过勾股定理来求。但是我们最后得到的是一个数值。而有可能在直线的后方相交。为了得到有向距离,我们还要用叉积来判断正负。

  • 要注意因为不能漏掉恰好重合的端点,所以我们要把差分的正负反一下。
  • 用的的公式 ,结合代码食用更佳。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define pii pair<double,long long> 
    long long n;double R,A,B;
    const int N = 2e6 + 100;
    struct Node{double x,y;}a[N];
    vector<pii> v;
    bool pd(int i) {
      double l = -B,r = A;
      double clac = l * a[i].y - a[i].x * r;
      return clac < 0;
    }
    int main() {
      scanf("%lld%lf%lf%lf",&n,&R,&A,&B);
      for(int i = 1;i <= n;i++) {
          scanf("%lf%lf",&a[i].x,&a[i].y);
          double X = a[i].x * a[i].x + a[i].y * a[i].y;
          double Y = A * A + B * B;
          double I = (B * a[i].x - A * a[i].y) * (B * a[i].x - A * a[i].y);
          if(I - R * R * Y > 1e-8) continue;
          double len1 = ((pd(i))?-1:1)*sqrt(X - I / Y) - ((R * R - I / Y)>1e-8 ? sqrt(R * R - I / Y) : 0.0);
          double len2 = ((pd(i))?-1:1)*sqrt(X - I / Y) + ((R * R - I / Y)>1e-8 ? sqrt(R * R - I / Y) : 0.0);
          v.push_back(pii(len1,-1));v.push_back(pii(len2,1));
      }
      sort(v.begin(),v.end());int ans = 0,last = 0;
      for(auto x:v) {ans = max(ans,last -= x.second);}
      cout << ans << endl;return 0;
    }