[CF1588E]Eligible Segments

2024-03-16 22:38
文章标签 segments cf1588e eligible

本文主要是介绍[CF1588E]Eligible Segments,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Eligible Segments

题解

一个点到 [ p i , p j ] [p_{i},p_{j}] [pi,pj]的线段的距离可以用该点到 [ p i , p j ) [p_{i},p_{j}) [pi,pj) [ p j , p i ) [p_{j},p_{i}) [pj,pi)这两条射线距离的最大值表示出来。
所以事实上,我们只需要让所有点到 [ p i , p j ) [p_{i},p_{j}) [pi,pj) [ p j , p i ) [p_{j},p_{i}) [pj,pi)两条射线的距离都小于 R R R,就可以说明所有点到 [ p i , p j ] [p_{i},p_{j}] [pi,pj]的距离小于 R R R

我们想想如果 p k p_{k} pk到一条从 p i p_{i} pi出发的射线的距离小于 R R R,那么这条射线应该往哪射。
显然,我们可以从 p k p_{k} pk做一个半径为 R R R的圆,在 p i p_{i} pi对于这个圆的两条切线形成的角内的射线,到 p k p_{k} pk的距离都小于 R R R
满足到所有点的距离都小于 R R R的条件,相当于在所有角的交内。
求切线就是一个简单的高中集合过程,你当然可以把交点都算出来,但事实上你只需要算切线角的角度与 [ p i , p k ) [p_{i},p_{k}) [pi,pk)的弧度,两个较大肯定是关于 [ p i , p k ) [p_{i},p_{k}) [pi,pk)对称的。
我们可以将所有角用弧度制表示成区间,我们的射线的弧度应该在这个区间内。
我们对于 p i p_{i} pi更新出它的合法区间后,查询一下有哪些 p j p_{j} pj在这个区间内即可。
最后看看有哪些两个方向的射线都满足条件就行了。

时间复杂度 O ( n 2 ) O\left(n^2\right) O(n2),但貌似常数有点大。

源码

#pragma GCC Optimize(2)
#pragma GCC Optimize(3)
#pragma GCC Optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 3005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double ld;      
const int INF=0x3f3f3f3f;    
const int mo=1e9+7;
const int inv2=499122177;
const double jzm=0.997;
const int zero=15;
const int n1=200;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){_T f=1;x=0;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int n,R,ans;bool mp[MAXN][MAXN];
double sqr(double x){return x*x;}
struct point{double x,y;point(){x=y=0;}point(double X,double Y){x=X;y=Y;}point operator + (const point &rhs)const{return point(x+rhs.x,y+rhs.y);}point operator - (const point &rhs)const{return point(x-rhs.x,y-rhs.y);}double angle(){return atan2(y,x);}double length(){return sqrt(sqr(x)+sqr(y));}
}p[MAXN];
double dist(point x,point y){return (x-y).length();}
signed main(){read(n);read(R);double r=R;for(int i=1,x,y;i<=n;i++)read(x),read(y),p[i]=point(x,y);for(int i=1;i<=n;i++){double L1=Pi,R1=-Pi,L2=-Pi,R2=Pi;for(int j=1;j<=n;j++){double tmp=dist(p[i],p[j]);if(tmp<=R)continue;double tp=(p[j]-p[i]).angle(),dt=asin(r/tmp);double tmp1=tp+dt;if(tmp1>Pi)tmp1-=Pi+Pi;double tmp2=tp-dt;if(tmp2<-Pi)tmp2+=Pi+Pi;if(Fabs(tmp1-tmp2)<Pi)L1=min(L1,max(tmp1,tmp2)),R1=max(R1,min(tmp1,tmp2));else L2=max(L2,max(tmp1,tmp2)),R2=min(R2,min(tmp1,tmp2));if(max(R1,L2)>L1&&min(L1,R2)<R1)break;}for(int j=1;j<=n;j++)if(i^j){double tmp=(p[j]-p[i]).angle();if(tmp<=L1&&tmp>=max(R1,L2))mp[i][j]=1;else if(tmp>=R1&&tmp<=min(L1,R2))mp[i][j]=1;}}for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)if(mp[i][j]&&mp[j][i])ans++;printf("%d\n",ans);return 0;
}

谢谢!!!

这篇关于[CF1588E]Eligible Segments的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/816957

相关文章

【ACdream】1157 Segments cdq分治

传送门:【ACdream】1157 Segments 题目分析:第一题cdq(陈丹琦)分治!cdq_____Orz! 听说cdq分治可以写,就去学了cdq分治了。。 在我们平常使用的分治中,每一个子问题只解决它本身(可以说是封闭的)。 而在cdq分治中,对于划分出来的两个子问题,前一个子问题用来解决后一个子问题而不是它本身。 具体算法流程如下: 1.将整个操作序列分为两个长

Codeforces Round 913 (Div. 3) D. Jumping Through Segments (二分*1400)

很容易看出这道题应该二分答案,本题的难点在于对于mid的验证。 找距离肯定是不难,难就难在我们输入的区间并不是按照左右顺序排列的,有的区间可能涵盖住了另一个区间,也就是说在这里我们需要进行的是左右的移动。 那么我们根本无法预知后面的线段在什么位置,所以并不能精准的对每次移动的距离进行一个控制,所以我们要采取向两边进行扩展的方法。 在一开始我们设定左右边界为0,每一次进行扩展的时候,我们就去

poj 3304 Segments(计算几何:叉积)

题目给出多条线段,问是否存在一条直线 使得所有投射到这条直线的线段至少有一个交点 也即判断是否存在一条直线与所有线段都相交 假设存在一条直线与所有线段都相交,那么我们一定可以通过平移、旋转等处理 使这条直线与两条或多条线段交于线段的端点处 我们就可以通过枚举所有端点再判断这样的直线是否满足条件即可 代码如下: /* ********************************

CVPR2017《Detecting Oriented Text in Natural Images by Linking Segments》阅读笔记

前言 本文是对CVPR2017《Detecting Oriented Text in Natural Images by Linking Segments》论文的简要介绍和细节分析。该论文是华中科大白翔组的工作,主要针对自然场景下文本检测模型由char-level到word-level和line-level的检测。 关键词:SSD、Segment、Link、Scene Text Detectio

lighoj 1088 Points in Segments | 二分

题意: 给你n个数,q个区间。让你求出每个区间所包含的数的个数。 思路: 一开始以为是线段树,不过看看数据范围,算了。。。 把n个数sort一遍,然后根据每个区间的两个边值进行二分,得出的结果相减即可。注意细节。 AC代码: #include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#in

题解:CF895B XK Segments

我的 CSDN 原文地址,转载请标明 这道题好水,就是不好理解而已…… 思路 暴力的复杂度是 n 2 n^2 n2 显然不可能通过 不难想到先排序,然后再使用二分查找。 lower_bound(begin, end, num) 可以返回一个有序序列的不小于 n u m num num 的值的地址,不存在则返回 e n d end end。常用用法:通过返回的地址减去起始地址 b e

POJ 3304 Segments 【计算几何】【直线和线段的关系】

题目链接:http://poj.org/problem?id=3304 题目大意:T个case,每个case里面有N条线段,判断能否存在一条直线,使得所有的线段在这条直线上都能有公共点,如果存在输出Yes,否则输出No。 题目的意思可以变成,在N条直线的2*N个端点中选择两个点组成一条直线能否满足这个条件,暴力枚举即可,注意的一点是在枚举的2*n个点中每次选择的两个点要判断是不是重复的。

Codeforces Round 943(Div.3) F.Equal XOR Segments

C o d e f o r c e s R o u n d 943 ( D i v . 3 ) F . E q u a l X O R S e g m e n t s \Huge{Codeforces~Round~943~(Div.3)F.Equal~XOR~Segments} Codeforces Round 943 (Div.3)F.Equal XOR Segments 文章目录 题

PAT A1104 Sum of Number Segments 中的隐式转换问题

题目本身不难,我一开始写的代码是 #include<stdio.h>int main(){int N;scanf("%d", &N);double ans = 0.0;for(int i=0; i<N; i++){double cur;scanf("%lf", &cur);ans += (i+1) * (N-i) * cur;}printf("%.2lf", ans);return 0;}

Codeforces Round #595 (Div. 3) D2 - Too Many Segments (hard version)(贪心)

题目链接:https://codeforces.com/contest/1249/problem/D2   题目大意:给出n个线段,问最少删几条边能够使得一个点最多被k条边覆盖   题目思路:比赛的时候一直想着线段树。。然后就歇逼了。。。其实就是个贪心,按照l排序,因为只有在l端点,一个点被覆盖的次数才会增加,所以出事的点一定是左端点。拿个multiset记录在当前点还有哪些边还存活着,存