"蔚来杯"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(1≤n≤105)个坐标 ( − 1 0 5 ≤ x , y ≤ 1 0 5 ) (-10^5\le x,y\le 10^5) (−105≤x,y≤105),顺次连成 n − 1 n-1 n−1个向量,求是否存在一条直线,是垂直于这条直线的每条线都最多交于这条折线的一个点。若有,则输出这条直线上任意两点的坐标 ( − 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)) (−109≤x1,y1,x2,y2≤109,(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;
}