1. 程式人生 > >2018.10.15 bzoj4445: [Scoi2015]小凸想跑步(半平面交)

2018.10.15 bzoj4445: [Scoi2015]小凸想跑步(半平面交)

傳送門 話說去年的省選計算幾何難度跟前幾年比起來根本不能做啊(雖然去年考的時候並沒有學過計算幾何) 這題就是推個式子然後上半平面交就做完了。 什麼? 怎麼推式子? 先把題目的概率轉換成求出可行區域。 然後用可行區域的面積比上總面積就是答案了。 我們設0號點(x1,y1)(x1,y1),1號點(x2,y2)(x2,y2),i號點(x3,y3)(x3,y3),i+1號點(x4,y4)(x4,y4) 然後由題可知cross(p0,p1)<cross(pi,pi+1)cross(p_0,p_1)<cross(p_i,p_{i+1})

然後化簡得: (y1y2y3+y4)x+(x1+x2+x3x4)y+cross(p0,p1)cross(pi,pi+1)>0(y1-y2-y3+y4)x+(-x1+x2+x3-x4)y+cross(p_0,p_1)-cross(p_i,p_{i+1})>0 這不就是半平面交嗎? 直接上半平面交就行了。 程式碼:

#include<bits/stdc++.h>
#define
N 200005
#define inf 2000000000 using namespace std; int n,tot,q[N],hd,tl,siz=0; struct Pot{double x,y;}p[N]; struct line{Pot a,b;}L[N]; inline Pot operator+(const Pot&a,const Pot&b){return (Pot){a.x+b.x,a.y+b.y};} inline Pot operator-(const Pot&a,const Pot&b){return (Pot){a.x-b.x,a.y-b.y};} inline
double operator^(const Pot&a,const Pot&b){return a.x*b.y-a.y*b.x;} inline double operator*(const Pot&a,const Pot&b){return a.x*b.x+a.y*b.y;} inline Pot operator*(const Pot&a,const double&b){return (Pot){a.x*b,a.y*b};} inline bool check(const Pot&a,const line&b){return ((a-b.a)^b.b)>=0;} inline Pot cross(const line&a,const line&b){return b.a+b.b*((a.b^(a.a-b.a))/(a.b^b.b));} inline int read(){ int ans=0,w=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();} while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans*w; } inline bool cmp(const line&a,const line&b){return atan2(a.b.y,a.b.x)<atan2(b.b.y,b.b.x);} int main(){ double sum1=0.0,sum2=0.0; n=read(); for(int i=1;i<=n;++i)p[i].x=read()*1.0,p[i].y=read()*1.0; for(int i=1;i<n;++i)sum2+=p[i]^p[i+1]; sum2+=p[n]^p[1]; L[++tot]=(line){p[2],p[1]-p[2]}; for(int i=2;i<=n-1;++i){ double a=p[1].y-p[2].y-p[i].y+p[i+1].y; double b=-p[1].x+p[2].x+p[i].x-p[i+1].x; double c=(p[1]^p[2])-(p[i]^p[i+1]); L[++tot]=(line){(Pot){b?0:-c/a,b?-c/b:0},(Pot){b,-a}}; } double a=p[1].y-p[2].y-p[n].y+p[1].y; double b=-p[1].x+p[2].x+p[n].x-p[1].x; double c=p[1].x*p[2].y-p[2].x*p[1].y-p[n].x*p[1].y+p[1].x*p[n].y; L[++tot]=(line){(Pot){b?0:-c/a,b?-c/b:0},(Pot){b,-a}}; L[++tot]=(line){(Pot){-inf,-inf},(Pot){0,1}}; L[++tot]=(line){(Pot){-inf,inf},(Pot){1,0}}; L[++tot]=(line){(Pot){inf,inf},(Pot){0,-1}}; L[++tot]=(line){(Pot){inf,-inf},(Pot){-1,0}}; sort(L+1,L+tot+1,cmp),siz=1; for(int i=2;i<=tot;++i){ if(atan2(L[i].b.y,L[i].b.x)-atan2(L[i-1].b.y,L[i-1].b.x)>1e-10)L[++siz]=L[i]; else if(check(L[i].a,L[siz]))L[siz]=L[i]; } q[hd=1]=1,q[tl=2]=2; for(int i=3;i<=siz;++i){ while(hd<tl&&!check(cross(L[q[tl-1]],L[q[tl]]),L[i]))--tl; while(hd<tl&&!check(cross(L[q[hd]],L[q[hd+1]]),L[i]))++hd; q[++tl]=i; } while(hd<tl&&!check(cross(L[q[tl-1]],L[q[tl]]),L[q[hd]]))--tl; while(hd<tl&&!check(cross(L[q[hd]],L[q[hd+1]]),L[q[tl]]))++hd; for(int i=hd;i<tl;++i)p[i-hd+1]=cross(L[q[i]],L[q[i+1]]); p[tl-hd+1]=cross((L[q[tl]]),L[q[hd]]); for(int i=1;i<=tl-hd;++i)sum1+=p[i]^p[i+1]; sum1+=p[tl-hd+1]^p[1]; printf("%.4lf",sum1/sum2); return 0; }