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

"蔚来杯"2022牛客暑期多校训练营4-M-Monotone Chain

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

题目大意

给定 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n\le 10^5) n(1n105)个坐标 ( − 1 0 5 ≤ x , y ≤ 1 0 5 ) (-10^5\le x,y\le 10^5) (105x,y105),顺次连成 n − 1 n-1 n1个向量,求是否存在一条直线,是垂直于这条直线的每条线都最多交于这条折线的一个点。若有,则输出这条直线上任意两点的坐标 ( − 1 0 9 ≤ x 1 , y 1 , x 2 , y 2 ≤ 1 0 9 , ( x 2 , y 2 ) ≠ ( 0 , 0 ) ) (-10^9\le x_1,y_1,x_2,y_2\le10^9,(x_2,y_2)\ne(0,0)) (109x1,y1,x2,y2109,(x2,y2)=(0,0)).

解题思路

首先要确定怎样判断某条直线的垂线是否经过两个向量。
如图,能够使每条垂线最多经过一点的直线的方向的范围,为以此向量为角平分线的平角的范围。

在这里插入图片描述
那多条向量所允许的直线的方向范围就是它们允许范围的交集,否则必有两条向量被同一垂线相交。
所以只需求出范围与交集,然后输出边界的方向即可。

代码实现

#include<bits/stdc++.h>
#define ll long long
#define x first
#define y second
#define pll pair<ll,ll>
using namespace std;
const int N=1e5+5;
ll n;
pll a[N],l,r,L,R;
ll operator ^(pll a,pll b){//这里用了叉乘的方法,也可用反三角函数求得。
	return a.x*b.y-a.y*b.x;
} 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
	L.x=L.y=1;
	for(int i=2;i<=n;i++){
		pll p;
		p.x=a[i].x-a[i-1].x;
		p.y=a[i].y-a[i-1].y;
		if(p.x==0&&p.y==0)continue;
        l.x=-p.y,l.y=p.x,r.x=p.y,r.y=-p.x;
		if(i==2){
			L=l,R=r;
			continue;
		}
		if((l^R)>0&&(r^L)<0){
			puts("NO");
			return 0;
		}
		if((l^L)>0)L=l;
		if((r^R)<0)R=r;
	}
	cout<<"YES\n0 0 "<<L.x<<' '<<L.y;
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值