【CF744D】Hongcow Draws a Circle 二分+幾何
阿新 • • 發佈:2018-03-04
復雜 pri 極角 開始 存在 pan while poi 二分答案
【CF744D】Hongcow Draws a Circle
題意:給你平面上n個紅點和m個藍點,求一個最大的圓,滿足圓內不存在藍點,且至少包含一個紅點。
$n,m\le 10^3$
題解:我們先不考慮半徑為inf的情況。顯然所求的圓一定是要與某個藍點相切的。我們可以先枚舉這個藍點,然後二分答案。當半徑已知、一個點固定時,圓的可能位置只能是繞著一個點旋轉得到的結果,其余的所有點都對應著極角上的一段區間,我們可以將這些區間排序,采用掃描線,看一下是否存在一段區間包含紅點且不包含藍點即可。
但是如果你仔細分析的話你會發現這樣的二分是不滿足單調性的。不過如果我們一開始不光枚舉藍點,還枚舉所有紅點,一起進行二分,這樣就滿足單調性了。
直接做的復雜度是$O(n\log ^2 n)$,會TLE,看了標程加了一些神優化才過~具體見代碼。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #define pi acos(-1.0) using namespace std; typedef long double db; const db eps=1e-12; const int maxn=1010; struct point { db x,y; point() {} point(db a,db b) {x=a,y=b;} point operator + (const point &a) const {return point(x+a.x,y+a.y);} point operator - (const point &a) const {return point(x-a.x,y-a.y);} db operator * (const point &a) const {return x*a.y-y*a.x;} point operator * (const db &a) const {return point(x*a,y*a);} }p[maxn<<1]; struct line { point p,v; line() {} line(point a,point b) {p=a,v=b;} }; struct node { db x; int k; node() {} node(double a,int b) {x=a,k=b;} }q[maxn<<3]; int n,m,tot; inline db dis(point a,point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } db getrange(point a,point b,db R) { db d=dis(a,b)/2; return acos(d/R); } bool cmp(const node &a,const node &b) {return a.x<b.x;} inline bool solve(int x,db R) { int i; tot=0; if(x<=n) q[++tot]=node(-pi,1),q[++tot]=node(pi,-1); else { for(i=1;i<=n;i++) { if(dis(p[i],p[x])>R+R-eps) continue; db a=getrange(p[x],p[i],R),b=atan2(p[i].y-p[x].y,p[i].x-p[x].x); db c=b-a,d=b+a; if(c<-pi) c+=2*pi; if(d>pi) d-=2*pi; if(c<d) q[++tot]=node(c,1),q[++tot]=node(d,-1); else q[++tot]=node(-pi,1),q[++tot]=node(d,-1),q[++tot]=node(c,1),q[++tot]=node(pi,-1); } } for(i=n+1;i<=n+m;i++) { if(dis(p[i],p[x])>R+R-eps) continue; db a=getrange(p[x],p[i],R),b=atan2(p[i].y-p[x].y,p[i].x-p[x].x); db c=b-a,d=b+a; if(c<-pi) c+=2*pi; if(d>pi) d-=2*pi; if(c<d) q[++tot]=node(c,-10000),q[++tot]=node(d,10000); else q[++tot]=node(-pi,-10000),q[++tot]=node(d,10000),q[++tot]=node(c,-10000),q[++tot]=node(pi,10000); } sort(q+1,q+tot+1,cmp); int tmp=0; for(i=1;i<=tot;i++) { if(tmp>0&&i!=1&&q[i].x>q[i-1].x+eps) return 1; tmp+=q[i].k; } return 0; } inline bool check(db mid) { for(int i=1;i<=n+m;i++) if(solve(i,mid)) return 1; return 0; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+(gc^‘0‘),gc=getchar(); return ret*f; } int main() { n=rd(),m=rd(); if(m==1) { puts("-1"); return 0; } int i; for(i=1;i<=n;i++) p[i].x=rd(),p[i].y=rd(); random_shuffle(p+1,p+n+1); for(i=1;i<=m;i++) p[i+n].x=rd(),p[i+n].y=rd(); random_shuffle(p+n+1,p+m+1); db l=0,r,mid; for(i=1;i<=n+m;i++) if(solve(i,l)) //神優化 { r=1e9; while(r-l>1e-5) { mid=(l+r)/2; if(solve(i,mid)) l=mid; else r=mid; } } if(l>1e9-1) puts("-1"); else printf("%.18Lf",l); return 0; }
【CF744D】Hongcow Draws a Circle 二分+幾何