P4250 [SCOI2015]小凸想跑步

Posted nofind

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4250 [SCOI2015]小凸想跑步相关的知识,希望对你有一定的参考价值。

题意

这题显然是暴推式子。

考虑下图:
技术图片
(S_{ABP}<S_{CDP}iff vec{AB}*vec{AP}<vec{CD}*vec{CP})

暴力展开可得:
((x_b-x_a,y_b-y_a) imes(x_p-x_a,y_p-y_a)<(x_d-x_c,y_d-y_c) imes(x_p-x_c,y_p-y_c))
((x_b-x_a)*(y_p-y_a)-(y_b-y_a)*(x_p-x_a)<(x_d-x_c)*(y_p-y_c)-(y_d-y_c)*(x_p-x_c))
化简得:
(x_p(y_a-y_b+y_d-y_c)+y_p(x_b-x_a+x_c-x_d)+((x_ay_b-x_by_a)-(x_cy_d-x_dy_c))<0)

这是条直线,我们用半平面交即可概率就是合法面积/总面积。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const double eps=1e-10;
const double inf=1e12;
int n,m;
double sum,ans;
struct Point
{
    double x,y;
    inline double len(){return sqrt(x*x+y*y);}
    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};}
    Point operator*(const double k){return (Point){x*k,y*k};}
    Point operator/(const double k){return (Point){x/k,y/k};}
    double operator*(const Point a)const{return x*a.y-y*a.x;}
    double operator&(const Point a)const{return x*a.x+y*a.y;}
}p[maxn],a[maxn<<1];
inline int dcmp(double x)
{
    if(fabs(x)<=eps)return 0;
    return x<0?-1:1;
} 
inline Point get(Point a,Point b){return b-a;}
struct Line
{
    Point p,v;double theta;
    bool operator<(const Line& a)const
    {
        return !dcmp(theta-a.theta)?dcmp(get(p,v)*get(p,a.v))<0:dcmp(theta-a.theta)<0;
    }
}line[maxn<<1],q[maxn<<1];
inline Point getpoint(Line l1,Line l2)
{
    Point p1=l1.p,v1=l1.v,p2=l2.p,v2=l2.v;
    v1=get(p1,v1),v2=get(p2,v2);
    Point u=get(p1,p2);
    return p2+v2*(u*v1)/(v1*v2);
}
inline bool check(Line a,Line b,Line c)
{
    Point p=getpoint(a,b);
    return dcmp(get(c.p,c.v)*get(c.p,p))<=0;
}
inline void solve()
{
    for(int i=1;i<=m;i++)line[i].theta=atan2(line[i].v.y-line[i].p.y,line[i].v.x-line[i].p.x);
    sort(line+1,line+m+1);
    int cnt=0;line[0].theta=inf;
    for(int i=1;i<=m;i++)if(line[i].theta!=line[i-1].theta)line[++cnt]=line[i];
    m=cnt;
    int l,r;
    q[l=r=1]=line[1];q[++r]=line[2];
    for(int i=3;i<=m;i++)
    {
        while(l<r&&check(q[r-1],q[r],line[i]))r--;
        while(l<r&&check(q[l],q[l+1],line[i]))l++;
        q[++r]=line[i];
    }
    while(l<r&&check(q[r-1],q[r],q[l]))r--;
    while(l<r&&check(q[l],q[l+1],q[r]))l++;
    cnt=0;
    q[r+1]=q[l];
    for(int i=l;i<=r;i++)a[++cnt]=getpoint(q[i],q[i+1]);
    a[cnt+1]=a[1];
    for(int i=1;i<=cnt;i++)ans+=a[i]*a[i+1];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
    p[n+1]=p[1];
    for(int i=1;i<=n;i++)
    {
        line[++m]=(Line){p[i],p[i+1],0};
        sum+=p[i]*p[i+1];
    }
    for(int i=2;i<=n;i++)
    {
        double a,b,c;
        a=p[1].y-p[2].y-p[i].y+p[i+1].y;
        b=p[2].x-p[1].x+p[i].x-p[i+1].x;
        c=p[1].x*p[2].y-p[2].x*p[1].y-p[i].x*p[i+1].y+p[i+1].x*p[i].y;
        Point p;
        if(!dcmp(b))p=(Point){-c/a,0};
        else p=(Point){0,-c/b};
        line[++m]=(Line){p,p+(Point){-b,a},0};
    }
    solve();
    printf("%.4lf",ans/sum);
    return 0;
} 

以上是关于P4250 [SCOI2015]小凸想跑步的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 4445: [Scoi2015]小凸想跑步

bzoj 4445 [SCOI2015] 小凸想跑步

[bzoj4445] [SCOI2015]小凸想跑步 (半平面交)

BZOJ4443[Scoi2015]小凸玩矩阵 二分+二分图最大匹配

BZOJ4443: [Scoi2015]小凸玩矩阵

bzoj4443[Scoi2015]小凸玩矩阵 二分+二分图匹配