【codeforces 566G】Max and Min 计算几何
题意:平面上有一个在第一象限的点(x,y),现在两个人(max 和 min) 分别有n,m个正向量,两个人轮流操作,max的操作是选择一个向量,使得点加上这个向量(可以选择多次),min则是减。如果某一刻这个点x<0, y < 0,min赢,反之max赢,问你哪个人赢。
首先,假如说有一个向量(a,b)(ab不同时=0),两个人选的向量在这个向量的投影中,谁的大,谁就赢。假如说max选择了多个向量的话,为了使得在某一个向量(a,b)上的投影来得大,那么还不如都选择投影最大的那个向量,所以max肯定会选择一个向量多次。
那么对于min呢?
假如说min当中存在 两个点,他们与原点构成的三角形,包含了 max 选的点,那么max这个点肯定赢不了(因为把该点延长,就会发现了)。
所以我们对min的点求个凸包(要加入 (0,ymax)和 (xmax , 0 ))
假如说不存在这两个点呢?那么max一定赢。
证明:假如说max选的点y 值 大于 ymax_min,则max一定赢,否则。在凸包上,假如(a,b)向量是 max选的向量的话,那么对于max附近的两个点,选择若干次可能会比max小,此时我们就要增加下方的min向量的数量,才使得在(a,b)上比max大,但是这样的话,min的y值就会比max的y值来的小,所以max必胜。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 1e5+9; 5 struct Point{ 6 ll x,y; 7 bool operator < (const Point& b)const{ 8 if(x==b.x) return y < b.y; 9 return x < b.x; 10 } 11 }pmx[N],pmn[N],ch[N]; 12 ll cross(Point a,Point b,Point c){ 13 return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y); 14 } 15 int Andrew(Point p[],int n,Point ch []){ 16 sort(p,p+n); 17 int m = 0; 18 for(int i = 0;i<n;++i){ 19 while(m>1 && cross(ch[m-2],p[i],ch[m-1])>=0 ) --m; 20 ch[m++] = p[i]; 21 } 22 int k = m; 23 for(int i = n-2;i>=0;--i){ 24 while(m>k && cross(ch[m-2],p[i],ch[m-1]) >= 0 ) --m; 25 ch[m++] = p[i]; 26 } 27 if(n>1) --m; 28 return m; 29 } 30 bool is_in(Point p,Point ch [],int n){ 31 //n>=2 32 int a = 1,b = n-1,c; 33 if(cross(ch[0],ch[a],ch[b]) > 0) swap(a,b); 34 // is_in allow on edge -> if( cross() > 0 || cross() < 0 ) 35 if( cross(ch[0],ch[a],p) >= 0 || cross(ch[0],ch[b],p) <= 0 ) return 0; 36 while( abs(a-b) > 1){ 37 c = (a+b)/2; 38 if( cross(ch[0],ch[c],p) > 0) b = c; 39 else a = c; 40 } 41 //is_in allow on edge -> return cross() <= 0 42 return cross(ch[a],ch[b],p) < 0; 43 } 44 int main(){ 45 int nmx,nmn; scanf("%d %d",&nmx,&nmn); 46 int x,y; scanf("%d %d",&x,&y); 47 for(int i = 0;i<nmx;++i) scanf("%lld %lld",&pmx[i].x,&pmx[i].y); 48 ll mx_y = 0,mx_x = 0; 49 for(int i = 0;i<nmn;++i){ 50 scanf("%lld %lld",&pmn[i].x,&pmn[i].y); 51 if(pmn[i].y > mx_y) mx_y = pmn[i].y; 52 if(pmn[i].x > mx_x) mx_x = pmn[i].x; 53 } 54 pmn[nmn++] = (Point){0,0}; 55 pmn[nmn++] = (Point){0,mx_y}; 56 pmn[nmn++] = (Point){mx_x,0}; 57 int m = Andrew(pmn,nmn,ch); 58 for(int i = 0;i<nmx;++i){ 59 if(!is_in(pmx[i],ch,m)){ 60 puts("Max"); 61 return 0; 62 } 63 } 64 puts("Min"); 65 return 0; 66 }