首页 > 代码库 > BZOJ3707 圈地

BZOJ3707 圈地

只会O(n ^ 3)路过= =

OrzOrzOrzOrzOrz

"出题人题解:

显然,这时候暴力枚举会T。于是我们转变一下思路,如果我们确定了2个点以后,第三个点有必要去盲目的枚举吗?答案是否定的。实际上我们把经过这两点的线看成一个斜率,把他当成y轴你会发现第三个点明显是在坐标系左右找一个离”y轴”最近的点来算面积更新答案。然后我们可以继续思考,发现我们可以把点按照某个斜率当成”y轴”进行“从左到右”的排序,这样当2点共线的时候,用这两个点的左右2个点去更新答案就好了。也就是说我们采用旋转坐标系的方法,一开始按x坐标排好序,认为直接用竖着的那条斜率,然后维护的话每次其实当两点共线后只要交换他们就能得到斜率转过该事件点的序列。所以我们可以预处理出所有可行的斜率,当成事件点,不断转动坐标系更新答案就好。这样复杂度只有n^2,期望得分100.(这确实只是个暴力的优化 啊。。。不要砸我T_T)"

 

 1 /************************************************************** 2     Problem: 3707 3     User: rausen 4     Language: C++ 5     Result: Accepted 6     Time:576 ms 7     Memory:16616 kb 8 ****************************************************************/ 9  10 #include <cstdio>11 #include <cmath>12 #include <algorithm>13  14 using namespace std;15 typedef double lf;16 const int N = 1005;17 const int M = N * N;18  19 struct points {20     lf x, y;21     points() {}22     points(lf _x, lf _y) : x(_x), y(_y) {}23 }p[N];24 inline bool operator < (const points &a, const points &b) {25     return a.x < b.x;26 }27  28 inline points operator - (const points &a, const points &b) {29     return points(a.x - b.x, a.y - b.y);30 }31  32 inline lf operator & (const points &a, const points &b) {33     return a.x * b.y - a.y * b.x;34 }35  36 struct lines {37     int p1, p2;38     lf S;39     lines() {}40     lines(int _p1, int _p2, lf _S) : p1(_p1), p2(_p2), S(_S) {}41 }l[M];42 inline bool operator < (const lines &a, const lines &b) {43     return a.S < b.S;44 }45  46 int n, tot;47 int w[N], a[N];48 lf ans = 1e60;49  50 inline int read() {51     int x = 0, sgn = 1;52     char ch = getchar();53     while (ch < 0 || 9 < ch) {54         if (ch == -) sgn = -1;55         ch = getchar();56     }57     while (0 <= ch && ch <= 9) {58         x = x * 10 + ch - 0;59         ch = getchar();60     }61     return sgn * x;62 }63  64 inline void calc(int i, int j, int k) {65     ans = min(ans, fabs((p[i] - p[k]) & (p[j] - p[k])) / 2);66 }67  68 int main() {69     int i, j, p1, p2;70     n = read();71     for (i = 1; i <= n; ++i)72         p[i].x = read(), p[i].y = read();73     sort(p + 1, p + n + 1);74     for (i = 1; i <= n; ++i)75         a[i] = w[i] = i;76     for (i = 1; i <= n; ++i)77         for (j = i + 1; j <= n; ++j)78             l[++tot] = lines(i, j, (p[j].y - p[i].y) / (p[j].x - p[i].x));79     sort(l + 1, l + tot + 1);80     for (i = 1; i <= tot; ++i) {81         p1 = l[i].p1, p2 = l[i].p2;82         if (w[p1] > w[p2]) swap(p1, p2);83         if (w[p1] > 1) calc(a[w[p1] - 1], p1, p2);84         if (w[p2] < n) calc(a[w[p2] + 1], p1, p2);85         swap(w[p1], w[p2]);86         swap(a[w[p1]], a[w[p2]]);87     }88     printf("%.2lf\n", ans);89     return 0;90 }
View Code

 (p.s. 话说那些Rank前4是怎么做到的= =内存和时间都很小的说Orz)

BZOJ3707 圈地