问题 D 视线

借鉴大佬:
https://www.cnblogs.com/albert-biu/p/10907996.html
对已有的代码进行详细解释
问题:
在这里插入图片描述
在这里插入图片描述如图所示
如果两个点可见的话,那么这两个点在圆上的四个切点存在公共区域,即图一和图二两种情况,所以只需要求出每一个点在圆上的两个切点(用弧度表示,范围【0 , 2*pi】),然后对于这些点进行排序,遍历每一对切点,找他们中间有多少个点,计算出来的结果除以二,为最后答案 即:ans=(∑(0,n) ai)/2

注意:

  1. atan() 与 atan2() 的区别 第一个范围(-90,90) 第二个范围(-180,180)
  2. 后边的计算中加上 2pi 为了把范围定位到(0,2pi)

在这里插入图片描述
4.lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100010;
const double pi=acos(-1);
struct point
{
    double x,y;
}a[maxn];
struct node
{
    double begin,end;
}e[maxn];
vector<double>s;
int main()
{
    int n;
    double r;
    cin>>n>>r;
    for(int i=0;i<n;i++)
    {
        cin>>a[i].x>>a[i].y;
        double len=sqrt(a[i].x*a[i].x+a[i].y*a[i].y);
        double r1=acos(r/len);
        double r2=atan2(a[i].y,a[i].x);
        //注意3
        e[i].begin=r2-r1+2*pi;
        e[i].end=r2+r1+2*pi;
        if(e[i].begin-2*pi>=0) e[i].begin-=2*pi;
        if(e[i].end-2*pi>=0) e[i].end-=2*pi;
        if(e[i].end-e[i].begin<=0) swap(e[i].end,e[i].begin);
        //
        s.push_back(e[i].begin);
        s.push_back(e[i].end);
    }
    long long ans=0;
    sort(s.begin(),s.end());
    long long from,to;
    for(int i=0;i<n;i++)
    {
        from=lower_bound(s.begin(),s.end(),e[i].begin)-s.begin();
        to=lower_bound(s.begin(),s.end(),e[i].end)-s.begin();
        if(e[i].end-e[i].begin-pi>=0)
        {
            ans=ans+2*n-(to-from-1)-2;
        }
        else
        {
            ans+=to-from-1;
        }
    }
    cout<<ans/2<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值