“蔚来杯“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 i<n) v =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<bits/stdc++.h>
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;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值