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

传送门
话说去年的省选计算几何难度跟前几年比起来根本不能做啊(虽然去年考的时候并没有学过计算几何)
这题就是推个式子然后上半平面交就做完了。
什么?
怎么推式子?
先把题目的概率转换成求出可行区域。
然后用可行区域的面积比上总面积就是答案了。
我们设0号点 ( x 1 , y 1 ) (x1,y1) (x1,y1),1号点 ( x 2 , y 2 ) (x2,y2) (x2,y2),i号点 ( x 3 , y 3 ) (x3,y3) (x3,y3),i+1号点 ( x 4 , y 4 ) (x4,y4) (x4,y4)
然后由题可知 c r o s s ( p 0 , p 1 ) &lt; c r o s s ( p i , p i + 1 ) cross(p_0,p_1)&lt;cross(p_i,p_{i+1}) cross(p0,p1)<cross(pi,pi+1)
然后化简得:
( y 1 − y 2 − y 3 + y 4 ) x + ( − x 1 + x 2 + x 3 − x 4 ) y + c r o s s ( p 0 , p 1 ) − c r o s s ( p i , p i + 1 ) &gt; 0 (y1-y2-y3+y4)x+(-x1+x2+x3-x4)y+cross(p_0,p_1)-cross(p_i,p_{i+1})&gt;0 (y1y2y3+y4)x+(x1+x2+x3x4)y+cross(p0,p1)cross(pi,pi+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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值