【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 }
View Code

 

posted @ 2020-03-25 21:12  小布鞋  阅读(268)  评论(0编辑  收藏  举报