【XSY3920】简单的几何题(几何,凸包)

题面

简单的几何题

题解

易知 v ≠ 0 v\neq 0 v=0,那么直接考虑条件:

( x i u 2 + x i − u v − y i v ) b 2 ≤ ( x i a 2 + x i − a b − y i b ) v 2 x i u 2 + x i − u v − y i v v 2 ≤ x i a 2 + x i − a b − y i b b 2 \begin{aligned} \left(x_iu^2+x_i-uv-y_iv\right)b^2&\leq \left(x_ia^2+x_i-ab-y_ib\right)v^2\\ \frac{x_iu^2+x_i-uv-y_iv}{v^2}&\leq\frac{x_ia^2+x_i-ab-y_ib}{b^2} \end{aligned} (xiu2+xiuvyiv)b2v2xiu2+xiuvyiv(xia2+xiabyib)v2b2xia2+xiabyib

u ′ = u v u'=\dfrac{u}{v} u=vu v ′ = 1 v v'=\dfrac{1}{v} v=v1 a ′ = a b a'=\dfrac{a}{b} a=ba b ′ = 1 b b'=\dfrac{1}{b} b=b1,则原不等式变为:

x i u ′ 2 + x i v ′ 2 − u ′ − y i v ′ ≤ x i a ′ 2 + x i b ′ 2 − a ′ − y i b ′ x_iu'^2+x_iv'^2-u'-y_iv'\leq x_ia'^2+x_ib'^2-a'-y_ib' xiu2+xiv2uyivxia2+xib2ayib

考虑配方:

x i u ′ 2 + x i v ′ 2 − u ′ − y i v ′ ≤ x i a ′ 2 + x i b ′ 2 − a ′ − y i b ′ u ′ 2 + v ′ 2 − 1 x i u ′ − y i x i v ′ ≤ a ′ 2 + b ′ 2 − 1 x i a ′ − y i x i b ′ ( u ′ 2 − 1 x i u ′ + 1 4 x i 2 ) + ( v ′ 2 − y i x i v ′ + y i 2 4 x i 2 ) ≤ ( a ′ 2 − 1 x i a ′ + 1 4 x i 2 ) + ( b ′ 2 − y i x i b ′ + y i 2 4 x i 2 ) ( u ′ − 1 2 x i ) 2 + ( v ′ − y i 2 x i ) 2 ≤ ( a ′ − 1 2 x i ) 2 + ( b ′ − y i 2 x i ) 2 \begin{aligned} x_iu'^2+x_iv'^2-u'-y_iv'&\leq x_ia'^2+x_ib'^2-a'-y_ib'\\ u'^2+v'^2-\frac{1}{x_i}u'-\frac{y_i}{x_i}v'&\leq a'^2+b'^2-\frac{1}{x_i}a'-\frac{y_i}{x_i}b'\\ \left(u'^2-\frac{1}{x_i}u'+\frac{1}{4x_i^2}\right)+\left(v'^2-\frac{y_i}{x_i}v'+\frac{y_i^2}{4x_i^2}\right) &\leq \left(a'^2-\frac{1}{x_i}a'+\frac{1}{4x_i^2}\right)+\left(b'^2-\frac{y_i}{x_i}b'+\frac{y_i^2}{4x_i^2}\right)\\ \left(u'-\frac{1}{2x_i}\right)^2+\left(v'-\frac{y_i}{2x_i}\right)^2 &\leq \left(a'-\frac{1}{2x_i}\right)^2+\left(b'-\frac{y_i}{2x_i}\right)^2 \end{aligned} xiu2+xiv2uyivu2+v2xi1uxiyiv(u2xi1u+4xi21)+(v2xiyiv+4xi2yi2)(u2xi1)2+(v2xiyi)2xia2+xib2ayiba2+b2xi1axiyib(a2xi1a+4xi21)+(b2xiyib+4xi2yi2)(a2xi1)2+(b2xiyi)2

其中左右分别可以看成是 ( u ′ , v ′ ) (u',v') (u,v) ( a ′ , b ′ ) (a',b') (a,b) 到同一个点 ( 1 2 x i , y i 2 x i ) \left(\dfrac{1}{2x_i},\dfrac{y_i}{2x_i}\right) (2xi1,2xiyi) 的距离,其中 ( a ′ , b ′ ) (a',b') (a,b) ( 1 2 x i , y i 2 x i ) \left(\dfrac{1}{2x_i},\dfrac{y_i}{2x_i}\right) (2xi1,2xiyi) 的距离是已知的,记为 R i R_i Ri

那么这个不等式就是要求 ( u ′ , v ′ ) (u',v') (u,v) 这个点在以 ( 1 2 x i , y i 2 x i ) \left(\dfrac{1}{2x_i},\dfrac{y_i}{2x_i}\right) (2xi1,2xiyi) 为圆心、 R i R_i Ri 为半径的圆内或圆上,记这个圆为圆 O i O_i Oi O i = ( 1 2 x i , y i 2 x i ) O_i=\left(\dfrac{1}{2x_i},\dfrac{y_i}{2x_i}\right) Oi=(2xi1,2xiyi)),那么 ⊙ O i \odot O_i Oi 过点 ( a ′ , b ′ ) (a',b') (a,b)

那么如果 i i i 是答案的一种,当且仅当存在点 ( u ′ , v ′ ) (u',v') (u,v) 满足它被 ⊙ O i \odot O_i Oi 包含(“包含” 指含边界),且 ∀ j ≠ i \forall j\neq i j=i ( u ′ , v ′ ) (u',v') (u,v) ⊙ O j \odot O_j Oj 外。也就是存在点 ( u ′ , v ′ ) (u',v') (u,v) 恰好只被圆 i i i 包含。

如何找到这些 i i i 呢?

我们考虑求出点集 { O , O 1 , O 2 , ⋯   , O n } \{O,O_1,O_2,\cdots,O_n\} {O,O1,O2,,On} 的凸包,那么 i i i 是答案的一种当且仅当 O i O_i Oi 在凸包上。

感性证明:(以下证明都十分感性,真正的证明应该是用反演变换化曲为直来证)

分情况讨论:

  • O O O 不在凸包上。

    那么考虑一个凸包内(不含边界)的点 A A A,显然一定可以找到两个在凸包上的相邻点 B , C B,C B,C 使得 A A A △ O B C \triangle OBC OBC 内,如图:

    在这里插入图片描述

    我们把这个三角形抽出来单独看,作出 ⊙ A , ⊙ B , ⊙ C \odot A,\odot B,\odot C A,B,C

    在这里插入图片描述

    ⊙ A \odot A A 的过点 O O O 的直径交 ⊙ A \odot A A 于另一点 P A P_A PA,同理设出 P B P_B PB P C P_C PC

    ⊙ B \odot B B ⊙ C \odot C C 交于点 Q Q Q,那么容易得到 ∠ P B Q O = ∠ P C Q O = 90 ° \angle P_BQO=\angle P_CQO=90° PBQO=PCQO=90°,那么 P B , Q , P C P_B,Q,P_C PB,Q,PC 三点共线。

    容易看出 △ P B O P C \triangle P_BOP_C PBOPC 是由 △ B O C \triangle BOC BOC 位似变换得到,所以 A A A △ B O C \triangle BOC BOC 内运动可以看作是 P A P_A PA △ P B O P C \triangle P_BOP_C PBOPC 内运动:(颜色可能有点变化,请不要在意)

    在这里插入图片描述

    那么容易看出 ⊙ B \odot B B ⊙ C \odot C C 的并集一定包含 ⊙ A \odot A A

    所以 ⊙ A \odot A A 所对应的 i i i 肯定不符合要求。

  • O O O 在凸包上。

    与第一种情况是类似的,对于凸包内(不含边界)的某一个点 A A A,同样一定可以找到两个在凸包上的相邻点 B , C B,C B,C 使得 A A A △ O B C \triangle OBC OBC 内,如图:

    在这里插入图片描述

    接下来的证明过程和第一种情况类似。

感性地证毕。

整道题的大致流程就是这样。

还有一个小细节,你发现如果用 double存点的话精度会爆炸。

然后又发现每一个点都是 ( x z , y z ) \left(\dfrac{x}{z},\dfrac{y}{z}\right) (zx,zy) 的形式,所以我们用三元组 ( x , y , z ) (x,y,z) (x,y,z) 存储一个点即可。

然后叉积判断等用 __int128即可,具体详见代码。

代码如下:(细节很多)

#include<bits/stdc++.h>
 
#define N 100010
#define ll long long
#define lll __int128
 
using namespace std;
 
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}
 
struct Point
{
    ll x,y,z;
    int id;
}p[N],st[N];
 
inline int check(Point a,Point b,Point c)
{
    lll x=(lll)(a.x*b.z-b.x*a.z)*(lll)(a.y*c.z-a.z*c.y);
    lll y=(lll)(a.x*c.z-c.x*a.z)*(lll)(a.y*b.z-a.z*b.y);
    if(x==y) return 0;
    return x<y?-1:1;
}
 
inline bool inside(Point a,Point b,Point c)
{
    if(a.x*b.z==b.x*a.z||b.x*c.z==c.x*b.z) return 1;
    return !((a.x*b.z<b.x*a.z)^(b.x*c.z<c.x*b.z));
}
 
inline bool operator < (Point a,Point b)
{
    int tmp=check(p[1],a,b);
    if(!tmp)
    {
        if(p[1].x*a.z<=a.x*p[1].z&&p[1].x*b.z<=b.x*p[1].z) return a.x*b.z<b.x*a.z;
        else return a.x*b.z>b.x*a.z;
    }
    return tmp>0;
}
 
inline bool operator == (Point a,Point b)
{
    return a.x*b.z==b.x*a.z&&a.y*b.z==b.y*a.z;
}
 
int n;
int top;
bool vis[N];
bool ban[N];
 
void Graham()
{
    for(int i=2;i<=n;i++)
        if(p[i].y*p[1].z<p[1].y*p[i].z||
        (p[i].y*p[1].z==p[1].y*p[i].z&&p[i].x*p[1].z<p[1].x*p[i].z))
            swap(p[1],p[i]);
    sort(p+2,p+n+1);
    st[++top]=p[1];
    for(register int i=2;i<=n;i++)
    {
        while(top>1)
        {
            int tmp=check(st[top-1],st[top],p[i]);
            if(!tmp&&st[top]==p[i]) ban[st[top].id]=ban[p[i].id]=1;
            if(tmp<0||(!tmp&&inside(st[top-1],st[top],p[i]))) top--;
            else break;
        }
        st[++top]=p[i];
    }
    for(register int i=1;i<=top;i++) vis[st[i].id]=1;
}
 
int main()
{
    n=read()+1;
    p[1].x=read(),p[1].y=1,p[1].z=read();
    for(register int i=2;i<=n;i++)
        p[i].x=1,p[i].z=2ll*read(),p[i].y=read(),p[i].id=i-1;
    Graham();
    for(register int i=1;i<n;i++)
        if(vis[i]&&!ban[i]) printf("%d ",i);
    return 0;
}
/*
1 2 3
4 5
*/
/*
2 2 3
4 5
6 7
*/
/*
2 1 666666666
333333333 1
455943374 506861437
*/
/*
2 236701642 822463349
213494995 807598793
728662831 347575608
*/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值