2019ICPC沈阳现场赛 E Capture Stars 圆的反演

https://ac.nowcoder.com/acm/contest/7830/D

感觉沈阳的惨败都是上个世纪的事情了。。。刚好牛客国庆集训3把沈阳的题放出来了,拿出来补补,就是个圆的反演水题,当时很多队很早就过了,然而最后也就那么多人过,因为2018-2019年的各种比赛题目中没出现过

这题就拿(0,0),半径为2*R当反演圆,然后两个过切点的圆反演过去就是两条直线,吧所有点反演过去就是直线之间的点,因为望远镜的区域跟原来的大圆小圆相切并夹在中间,反演过去就也是夹在中间相切的,半径就知道了,横坐标也是确定的

然后我们可以求出每个点包含他的圆的圆心的纵坐标的范围,因为不能在边界上,所以规定一下左闭右开,按l排序,然后用个堆或者multiset每次找出最小的丢进去的r看要不要弹出就行了

 

#include<bits/stdc++.h>
using namespace std;

const double eps=1e-8;
inline int sgn(double x)
{
	if(fabs(x)<eps) return 0;
	if(x<0) return -1;
	else 	return 1;
}
inline double mysqrt(double x)
{
	return sqrt(max(x,0.0));
}

struct point
{
	double x,y;
	point(double a=0,double b=0)
	{
		x=a;y=b;
	}
	point operator + (const point &b)const
	{
		return point(x+b.x,y+b.y);
	}
	point operator - (const point &b)const
	{
		return point(x-b.x,y-b.y);
	}
	friend point operator * (const point &p,double t)
	{
		return point(t*p.x,t*p.y);
	}
	double norm()
	{
		return mysqrt(x*x+y*y);
	}
};
struct circle
{
	point o;double r;
	circle(point a=point(0,0),double R=0)
	{
		o=a;r=R;
	}
};

const int maxl=1e4+10;

int n,tot,ans; 
point a[maxl],b[maxl];
double r,R,lb,rb;
circle c;
struct seg
{
	double l,r;
}se[maxl];
priority_queue<double,vector<double>,greater<double> >q;

inline point inverse_point(point p,circle a)
{
	point res;
	double len=(p-a.o).norm();
	double len2=a.r*a.r/len;
	res=a.o+(p-a.o)*(len2/len);
	return res;
}

inline void prework()
{
	scanf("%d",&n);
	scanf("%lf%lf",&R,&r);
	c.o=point(0,0);c.r=2*R;
	lb=2*R;rb=2*R*2*R/(2*r);
	double dx,dy,dr=(rb-lb)/2;
	tot=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%lf%lf",&a[i].x,&a[i].y);
		b[i]=inverse_point(a[i],c);
		dx=fabs(b[i].x-((lb+rb)/2));
		dy=mysqrt(dr*dr-dx*dx);
		se[i]=seg{b[i].y-dy,b[i].y+dy};
	}
}

inline bool cmp(const seg &a,const seg&b)
{
	if(sgn(a.l-b.l)==0)
		return a.r<b.r;
	return a.l<b.l;
}

inline void mainwork()
{
	int num=0;ans=0;
	sort(se+1,se+1+n,cmp);
	while(!q.empty())
		q.pop();
	for(int i=1;i<=n;i++)
	{
		q.push(se[i].r);num++;
		while(q.top()<se[i].l+eps)
		{
			num--;
			q.pop();
		}
		ans=max(ans,num);
	}
}

inline void print()
{
	printf("%d\n",ans);
}

int main()
{
	int t;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值