• “蔚来杯“2022牛客暑期多校训练营4 M题: Monotone Chain


    M题: Monotone Chain

    原题链接:https://ac.nowcoder.com/acm/contest/33189/M

    题目大意

    多边形链由一系列相连的线段构成,可以表示为一系列线段的端点 { A 1 , A 2 , . . . , A n } \{A_1,A_2,...,A_n\} {A1,A2,...,An}

    给定射线 L a , b = { a + λ b ∣ λ ∈ R } L_{a,b}=\{a+\lambda b|\lambda \in \R \} La,b={a+λbλR} ,定义多边形链 C = { A 1 , A 2 , . . . , A n } C=\{A_1,A_2,...,A_n\} C={A1,A2,...,An} 单调于射线 L a , b L_{a,b} La,b ,当且仅当:

    • ∀ 1 ≤ i < j ≤ n , ( O A i − a ) ⋅ b ≤ ( O A j − a ) ⋅ b \forall 1\le i< j\le n,(OA_i-a)⋅b \le(OA_j-a)⋅b ∀1i<jn,(OAia)b(OAja)b
      其中 O A i OA_i OAi 表示 A i A_i Ai 的坐标, ⋅ ⋅ 表示向量的点乘

    给定 n n n 个点的多边形链 C C C ,判断是否存在射线 L a , b L_{a,b} La,b 使得多边形链 C C C 单调于射线 L a , b L_{a,b} La,b ,若有则求出任意解。

    题解

    ∀ v ⃗ = A i A i + 1 ( 1 ≤ i < n ) \forall \vec{v}=A_iA_{i+1}(1\le iv =AiAi+1(1i<n) ,发现射线 L a , b L_{a,b} La,b 的方向与 v ⃗ \vec{v} v 的夹角应不超过 90 ° 90° 90° ,换句话说,射线的方向都在以 v ⃗ \vec{v} v 为角平分线的平角范围内。
    不妨对所有的 v ⃗ \vec{v} v 求出可行的射线方向范围,然后验证是否有交集即可
    当表示方向的范围时,可以用向量来保存两个边界(逆时针的最大方向与顺时针的最大方向),然后用叉乘判断交集是否存在即可。

    参考代码

    #include
    using namespace std;
    
    template<class T>inline void read(T&x){//快读
    	char c,last=' ';
    	while(!isdigit(c=getchar()))last=c;
    	x=c^48;
    	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+(c^48);
    	if(last=='-')x=-x;
    }
    
    #define ll long long
    const int MAXN=1e5+5;
    int n;
    
    struct Point{//向量表示
    	ll x,y;
    }P[MAXN];
    
    ll operator^(Point&a,Point&b){//叉乘,用于判断方向
    	return a.x*b.y-a.y*b.x;
    } 
    
    int main()
    {
    	read(n);
    	for(int i=1;i<=n;++i)read(P[i].x),read(P[i].y);
    	bool ok=0;//0表示还没有初始化
    	Point L={1,1},R;//若所有点都重合时,输出0 0 1 1作为答案
    	for(int i=1;i<n;++i){
    		Point p={P[i+1].x-P[i].x,P[i+1].y-P[i].y},l,r;//求出折线当前段
    		if(p.x==0&&p.y==0)continue;//如果两点重合,跳过
    		l={-p.y,p.x},r={p.y,-p.x};//l表示以当前段作为角平分线时的逆时针边界,r表示顺时针边界
    		if(!ok){//还没有初始化,则将当前范围直接作为交集
    			ok=1;
    			L=l,R=r;
    			continue;
    		}
    		if((l^R)>0&&(r^L)<0){//出现无交集的情况,即无解
    			puts("NO");exit(0);
    		}
    		if((l^L)>0)L=l;//逆时针边界缩小
    		if((r^R)<0)R=r;//顺时针边界缩小
    	}
    	puts("YES");
    	cout<<"0 0 "<<L.x<<' '<<L.y<<'\n';//因为是闭区间,直接取边界作为答案即可
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
  • 相关阅读:
    软件开发行业的乱象——低价引流中途收费?299?399?
    【java8】阿里架构师:Stream对集合的处理方式你全都知道了吗?
    【机器学习】【深度学习】批量归一化(Batch Normalization)
    心脏出血漏洞复现(CVE-2014-0160)
    java计算机毕业设计美食推荐管理系统源码+系统+mysql数据库+lw文档
    设计模式 - 概览
    【python与数据结构】(leetcode算法预备知识)
    开源python双屏图片浏览器软件
    CSDN【top1】Pytest接口测试框架实战项目搭建
    LFS学习系列3 — 前言
  • 原文地址:https://blog.csdn.net/Spy_Savior/article/details/126084611