传送门

wwwwwwwwwwwwwwwwwww

我已经不知道这串w是什么意思了

一开始以为是什么高大上的东西,钻研了会$P$点的性质。后来发现就是列个式子的事。

三角形的面积,两边叉积的一半,把这个叉积写开:

$\overrightarrow{PP_i}\times\overrightarrow{PP_{i+1}}$

$=(p_i-p)\times(p_{i+1}-p)$

$=p_i\times p_{i+1}-p_i\times p-p\times p_{i+1}$

$=x(y_i-y_{i+1})+y(x_{i+1}-x_i)+p_i\times p_{i+1}$

再把条件“$p_0,p_1,p$围成的三角形面积最小”写开:

$\overrightarrow{PP_i}\times\overrightarrow{PP_{i+1}}>\overrightarrow{PP_0}\times\overrightarrow{PP_1}$

$x(y_i-y_{i+1})+y(x_{i+1}-x_i)+p_i\times p_{i+1}>x(y_0-y_1)-y(x_1-x_0)+p_0\times p_1$

$x(y_i-y_{i+1}-y_0+y_1)+y(x_{i+1}-x_i-x_1+x_0)+p_i\times p_{i+1}-p_0\times p_1>0$

半平面交显然。由于点$P$要在凸多边形内,还要和凸多边形交一下。答案算个面积之比就好了。

然而很玄学的是不能直接代$x=0,1$(或者$y=0,1$)表示直线,貌似是因为坐标太大叉乘就炸了。然而代$x=0$和$x=0$加上向量$(b,-a)$就过了。。。

感觉两种方法没有本质上的区别啊,有没有大佬解释一下啊。。。

这题好就好在不怎么卡精度,开个long double就过了,甚至可以不设eps直接比。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>

#define maxn 200005
#define double long double

const double eps = 1e-18;
const double inf = 1e18;
const double pi = acos(-1.0);

using namespace std;

inline int read(){
    int x=0,y=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return y?-x:x;
}
inline int cmp(double x,double y){return x-y>eps?1:x-y<-eps?-1:0;}
struct point{
    double x,y;
    point(double X=0,double Y=0){x=X,y=Y;}
    point operator + (const point &a){return point(x+a.x,y+a.y);}
    point operator - (const point &a){return point(x-a.x,y-a.y);}
    point operator * (const double &a){return point(x*a,y*a);}
    point operator / (const double &a){return point(x/a,y/a);}
    double alpha(){return atan2(y,x);}
}p[maxn],P;
struct line{
    point a,b;
    double an;
    line(point A=point(0,0),point B=point(0,0)){a=A,b=B,an=(b-a).alpha();}
}l[maxn],q[maxn];
struct circle{
    point c;
    double r;
    circle(point C=point(0,0),double R=0){c=C,r=R;}
    circle(point A,point B,point C){
#define sqr(x) ((x)*(x))
        double a=sqr(A.x)-sqr(B.x)+sqr(A.y)-sqr(B.y),b=sqr(B.x)-sqr(C.x)+sqr(B.y)-sqr(C.y),_c=A.x-B.x,d=A.y-B.y,e=B.x-C.x,f=B.y-C.y,m=2*(_c*f-d*e);
        c=point((a*f-b*d)/m,(b*_c-a*e)/m);
        r=sqrt(sqr(A.x-c.x)+sqr(A.y-c.y));
#undef sqr
    }
};
typedef vector<point> polygon;
inline double abs2(point a){return a.x*a.x+a.y*a.y;}
inline double abs(point a){return sqrt(abs2(a));}
inline double dis(point &a,point &b){return abs(a-b);}
inline double dot(point a,point b){return a.x*b.x+a.y*b.y;}
inline double cross(point a,point b){return a.x*b.y-a.y*b.x;}
inline double angle(line &a){return (a.b-a.a).alpha();}
inline point rotate(point a,double b){return point(a.x*cos(b)-a.y*sin(b),a.x*sin(b)+a.y*cos(b));}
inline point inter(line a,line b){
    point A=a.b-a.a,B=b.b-b.a;
    return a.a+A*cross(B,a.a-b.a)/cross(A,B);
}
inline double area(polygon &a){
    double ans=0;
    for(register int i=0,j=a.size()-1;i<a.size();j=i++)ans+=cross(a[j],a[i]);
    return ans/2.0;
}
polygon u,v;
inline bool mmp(line &a,line &b){
    if(a.an==b.an)return cross(b.b-a.a,b.a-a.a)<0.0;
    return a.an<b.an;
}
inline bool judge(point &a,line &b){return cross(b.b-a,b.a-a)>0.0;}
int main(){
    int n=read(),cnt=0,h=1,t=0;
    for(register int i=1;i<=n;++i){
        P.x=read(),P.y=read();
        v.push_back(P);
    }
    for(register int i=0,j=n-1;i<n;j=i++){
        l[++cnt]=line(v[j],v[i]);
        if(i==1)continue;
        double a=v[j].y-v[i].y-v[0].y+v[1].y,b=v[i].x-v[j].x-v[1].x+v[0].x,c=cross(v[j],v[i])-cross(v[0],v[1]);
        if(cmp(a,0))l[++cnt]=line(point(-c/a,0),point(-c/a+b,-a));
        else if(cmp(b,0))l[++cnt]=line(point(0,-c/b),point(b,-c/b-a));
    }
    sort(l+1,l+1+cnt,mmp);
    for(register int i=1;i<=cnt;++i){
        if(i!=1&&angle(l[i])==angle(l[i-1]))continue;
        while(t-h>=1&&judge(p[t],l[i]))--t;
        while(t-h>=1&&judge(p[h+1],l[i]))++h;
        q[++t]=l[i];
        if(t-h>=1)p[t]=inter(q[t],q[t-1]);
    }
    while(t-h>=1&&judge(p[t],q[h]))--t;
    u.push_back(inter(q[h],q[t]));
    for(register int i=h+1;i<=t;++i)u.push_back(p[i]);
    printf("%.4Lf\n",area(u)/area(v));
}