bzoj 1069 [SCOI2007]最大土地面积

看了黄学长的博客才知道是旋转卡壳的裸题,我似乎是用暴力卡过的

首先这四个点一定在凸包上,要先把凸包搞出来(忘了判重点WA了一个小时QAQ),

因为n的范围很小,所以我们可以直接枚举这个四边形的对角线,分别找这条对角线两边的点与这条线组成的最大三角形

因为是一个凸包所以我们可以三分,但实际上这是有决策单调性的,所以直接上旋转卡壳就可以过了

 1 #define MAXN 4010UL
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 
 8 int n, hd, tl, T, num;
 9 double ans;
10 
11 struct Point {
12     double x, y;
13     friend double operator * (Point a, Point b) {
14         return a.x*b.y-a.y*b.x;
15     }
16     friend Point operator - (Point a, Point b) {
17         return (Point){a.x-b.x, a.y-b.y};
18     }
19     friend bool operator < (Point a, Point b) {
20         return a.x==b.x?a.y<b.y:a.x<b.x;
21     }
22 }pt[MAXN<<1], q[MAXN<<1];
23 
24 bool Check(Point a, Point b) {
25     return a*b<=0;
26 }
27 
28 double F(Point a, Point b, Point c) {
29     
30     return fabs(a*b+b*c+c*a)/2.;
31 }
32 
33 int Solve(Point a, Point b, int l, int r) {
34     ++ num;
35     double ret = -1.;
36     int pos;
37     while(r-l>=3) {++ T;
38         int mid = (l+r)>>1, midd = (mid+r)>>1;
39         if(F(a, b, pt[mid])>F(a, b, pt[midd])) r = midd-1;
40         else l = mid+1;
41     }
42     for(int i = l ; i <= r ; ++ i) {
43         double w = F(a, b, pt[i]);
44         if(ret<w) ret = w, pos = i;
45     }
46     return pos;
47 }
48 
49 int main() {    
50     scanf("%d", &n);
51     for(int i = 1 ; i <= n ; ++ i) scanf("%lf%lf", &pt[i].x, &pt[i].y);
52     sort(pt+1, pt+n+1);
53     for(int i = 1 ; i <= n ; ++ i) {
54         while(hd+1<tl&&Check(q[tl-1]-q[tl-2], pt[i]-q[tl-1])) -- tl;
55         q[tl ++] = pt[i];
56     }
57     for(int i = n-1 ; i >= 2 ; -- i) {
58         while(hd+1<tl&&Check(q[tl-1]-q[tl-2], pt[i]-q[tl-1])) -- tl;
59         q[tl ++] = pt[i];
60     }
61     while(hd+1<tl&&Check(q[tl-1]-q[tl-2], q[hd]-q[tl-1])) -- tl;
62     int ti = 0;
63     for(int i = hd ; i < tl ; ++ i) ++ ti, pt[ti] = q[i], pt[ti+tl-hd] = q[i];
64     for(int i = 1 ; i <= ti ; ++ i) {
65         int lt1 = 0, lt2 = 0;
66         for(int j = i+2 ; j <= ti ; ++ j) if(j-i>=2&&i+ti-j>=2) {
67             lt1 = Solve(pt[i], pt[j], i+1, j-1), lt2 = Solve(pt[i], pt[j], j+1, i+ti-1);
68             double w = F(pt[i], pt[j], pt[lt1])+F(pt[i], pt[j], pt[lt2]);
69             if(ans<w) ans = w;
70         }
71     }
72     printf("%.3lf", ans);
73     return 0;
74 }
View Code

 

posted @ 2016-04-27 09:44  assassain  阅读(204)  评论(0编辑  收藏  举报