1. 程式人生 > >BZOJ2732[HNOI2012]射箭

BZOJ2732[HNOI2012]射箭

題目大意

給出N條垂直於x軸的線段,求最大的K,使得存在一條經過原點,開口向下的拋物線穿過前K條線段(經過端點也算穿過),保證N條線段不重疊,且都在第一象限。

輸入輸出

第一行為一個整數N;

接下來N行每行3個整數x,y1,y2,描述一條線段。

資料範圍

N≤100000,0<x≤1e9,0<y1<y2≤1e9。

解析

設拋物線方程為ax2+bx,則y1≤ax2+bx≤y2;

可以把每條線段看成兩個關於a,b的不等式,由於是一次的,可以用半平面交驗證答案。於是二分K,驗證是否可行。

幾個細節:

1)半平面在向量哪邊要想清楚;

2)由於經過端點也算穿過,所以半平面交的邊上也是可行的,極端情況所有直線交於一點,不知道有沒有這種資料;

3)拋物線開口向下,對稱軸在第一象限,增加2個向量限制a<0,b>0;

4)為了方便判斷半平面交是否為空,可以增加2個“邊框”向量,但是這兩個向量的起止點座標要足夠大(反正我開1e12WA了);

5)開long double;

6)全部排序後根據id加入半平面交O(nlogn)比每次二分都排一次序O(nlog2n)優秀(廢話)。

程式碼

        一直T竟然是因為求交點的方法不夠優秀,程式碼過於醜陋必須加讀入優化才能過qwq。

  1 #include <cstdio>
  2 #include <cstring>
  3
#include <iostream> 4 #include <iomanip> 5 #include <cmath> 6 #include <algorithm> 7 8 typedef long long LL; 9 typedef long double LD; 10 const LD INF = 1e15; 11 struct Point { 12 LD x, y; 13 Point(LD _x = 0, LD _y = 0):x(_x), y(_y) {}; 14 }; 15 struct Vector { 16
Point st, ed; 17 int id; 18 LD arg; 19 Vector() { memset(this, 0, sizeof(Vector)); } 20 Vector(Point _st, Point _ed):st(_st), ed(_ed), id(0) {}; 21 bool operator <(const Vector &) const; 22 friend LD cross(const Vector &, const Vector &); 23 friend Point intersection(const Vector &, const Vector&); 24 } line[200010]; 25 int N; 26 27 bool judge(int); 28 bool check(const Vector &, const Vector &, const Vector &); 29 inline char gc(); 30 inline int read(); 31 32 int main() { 33 #ifndef ONLINE_JUDGE 34 freopen("2732.in", "r", stdin); 35 freopen("2732.out", "w", stdout); 36 #endif 37 N = read(); 38 line[0] = Vector(Point(0, -INF), Point(0, INF)); 39 line[1] = Vector(Point(-INF, 0), Point(INF, 0)); 40 for (int i = 1; i <= N; i++) { 41 LD x = read(), y1 = read(), y2 = read(); 42 line[i << 1] = Vector(Point(-1, y1 / x + x), Point(1, y1 / x - x)); 43 line[i << 1 | 1] = Vector(Point(1, y2 / x - x), Point(-1, y2 / x + x)); 44 line[i << 1].id = line[i << 1 | 1].id = i; 45 } 46 int l = 1, r = N; 47 N = (N << 1 | 1); 48 line[++N] = Vector(Point(-INF, INF), Point(-INF, -INF)); 49 line[++N] = Vector(Point(INF, INF), Point(-INF, INF)); 50 for (int i = 0; i <= N; i++) 51 line[i].arg = atan2(line[i].ed.y - line[i].st.y, line[i].ed.x - line[i].st.x); 52 std::sort(line, line + N + 1); 53 while (l < r) { 54 int mid = (l + r + 1) >> 1; 55 if (judge(mid)) l = mid; 56 else r = mid - 1; 57 } 58 printf("%d\n", l); 59 60 return 0; 61 } 62 bool Vector::operator <(const Vector &v) const { 63 if (arg != v.arg) return arg < v.arg; 64 else return cross(*this, Vector(st, v.st)) <= 0; 65 } 66 LD cross(const Vector &a, const Vector &b) { 67 return (a.ed.x - a.st.x) * (b.ed.y - b.st.y) - (a.ed.y - a.st.y) * (b.ed.x - b.st.x); 68 } 69 Point intersection(const Vector &a, const Vector &b) { 70 LD s1 = cross(Vector(a.st, b.ed), a); 71 LD s2 = cross(a, Vector(a.st, b.st)); 72 LD t = s2 / (s1 + s2); 73 return Point(b.st.x + t * (b.ed.x - b.st.x), b.st.y + t * (b.ed.y - b.st.y)); 74 } 75 bool check(const Vector &a, const Vector &b, const Vector &c) { 76 Point p = intersection(a, b); 77 return cross(Vector(c.st, p), c) > 0; 78 } 79 bool judge(int lim) { 80 static Vector ls[200010], res[200010]; 81 int tot = 0, head = 0, tail = 0; 82 for (int i = 0; i <= N; i++) 83 if (line[i].id <= lim) ls[tot++] = line[i]; 84 for (int i = 0; i < tot; i++) { 85 if (i && ls[i].arg == ls[i - 1].arg) continue; 86 while (tail - head > 1 && check(res[tail - 2], res[tail - 1], ls[i])) tail--; 87 while (tail - head > 1 && check(res[head], res[head + 1], ls[i])) head++; 88 res[tail++] = ls[i]; 89 } 90 while (tail - head > 2 && check(res[tail - 2], res[tail - 1], res[head])) tail--; 91 while (tail - head > 2 && check(res[head], res[head + 1], res[tail - 1])) head++; 92 return tail - head > 2; 93 } 94 inline char gc() { 95 static char buf[1000000], *p1, *p2; 96 if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin); 97 return p1 == p2 ? EOF : *p2++; 98 } 99 inline int read() { 100 int res = 0, op = 1; 101 char ch = gc(); 102 while (ch != '-' && (ch < '0' || ch > '9')) ch = gc(); 103 if (ch == '-') op = 1, ch = gc(); 104 while (ch >= '0' && ch <= '9') 105 res = (res << 1) + (res << 3) + ch - '0', ch = gc(); 106 return res * op; 107 }