射箭(程序文件名:archery.exe)100 分,运行时限:1s
沫沫最近在玩一个二维的射箭游戏,如下图 1 所示,这个游戏中的 x 轴在地面,第一象限中有一些竖直线段作为靶子,任意两个靶子都没有公共部分,也不会接触坐标轴。
沫沫控制一个位于(0,0)的弓箭手,可以朝 0 至 90°中的任意角度(不包括 0°和 90°),以任意大小的力量射出带有穿透能力的光之箭。由于游戏中没有空气阻力,并且光之箭没有箭身,箭的轨迹会是一条标准的抛物线,被轨迹穿过的所有靶子都认为被沫沫射中了,包括那些只有端点被射中的靶子。
这个游戏有多种模式,其中沫沫最喜欢的是闯关模式。在闯关模式中,第一关只有一个靶子,射中这个靶子即可进入第二关,这时在第一关的基础上会出现另外一个靶子,若能够一箭
双雕射中这两个靶子便可进入第三关,这时会出现第三个靶子。依此类推,每过一关都会新出现一个靶子,在第 K 关必须一箭射中前 K 关出现的所有 K 个靶子才能进入第 K+1 关,否则游戏结束。
沫沫花了很多时间在这个游戏上,却最多只能玩到第七关“七星连珠”,这让她非常困惑。
于是她设法获得了每一关出现的靶子的位置,想让你告诉她,最多能通过多少关。
对于每一关 (x, y1, y2), 有 ax2 + bx >= y1, ax2 + bx <= y2, 再把 a 当作 x,b 当作 y,原式变为 kx + ly >= q, 就可以发现就是线性规划。
很容易秒出 O(nlg2n) 的算法,就是对前面每一关做一次半平面交。然后就马上可以想到二分答案了。
对于小于等于号的处理,我对于大的一方加上了一个 eps 。
然后就是这道题卡精度。。。。加了 5 个 0 就 A 了。。。
Code :
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 200007
#define R(a) const a &
#define oo 1000000000000000000.
#define eps 0.00000000000000001
struct point{double x, y;};
struct line{point f; double c;};
double operator *(R(point) a) {return sqrt(a.x * a.x + a.y * a.y);}
double operator *(R(point) a, R(point) b) {return a.x * b.y - a.y * b.x;}
double operator /(R(point) a, R(point) b) {return a.x * b.x + a.y * b.y;}
point operator *(R(line) a, R(line) b)
{
R(double) c = a.f * b.f;
return (point) {(b.f.y * a.c - a.f.y * b.c) / c, (a.f.x * b.c - b.f.x * a.c) / c};
}
int n, m, * h, * t, l, r, mid;
int p[maxn], q[maxn], map[maxn], pp[maxn];
double x, y, z;
double d[maxn], e[maxn];
line a[maxn];
int lfcmp(R(double) a, R(double) b)
{
R(double) c = a - b;
if (c < - eps) return - 1;
else return c > eps;
}
bool cmp(R(int) i, R(int) j)
{
return d[i] < d[j] || (! lfcmp(d[i], d[j]) && e[i] > e[j]);
}
void getline(R(double) x, R(double) y, R(double) z)
{
a[++ m] = (line) {(point) {x, y}, z};
p[m] = m, d[m] = atan2(y, x), e[m] = z / * a[m].f;
}
bool okay(int n)
{
int tot = 0; h = q + 1, t = q;
for (int i = 1; i <= m; ++ i) if (map[p[i]] <= n) pp[++ tot] = p[i];
for (int i = 1; i <= tot; ++ i) if (i == 1 || lfcmp(d[pp[i]], d[pp[i - 1]]))
{
while (t - h > 0 && a[* t] * a[* (t - 1)] / a[pp[i]].f < a[pp[i]].c + eps) -- t;
while (t - h > 0 && a[* h] * a[* (h + 1)] / a[pp[i]].f < a[pp[i]].c + eps) ++ h;
* (++ t) = pp[i];
}
while (t - h > 1 && a[* t] * a[* (t - 1)] / a[* h].f < a[* h].c + eps) -- t;
while (t - h > 1 && a[* h] * a[* (h + 1)] / a[* t].f < a[* t].c + eps) ++ h;
return t - h > 1;
}
int main()
{
scanf("%d", & n);
for (int i = 1; i <= n; ++ i)
{
scanf("%lf%lf%lf", & x, & y, & z);
getline(x * x, x, y - eps), map[m] = i;
getline(- x * x, - x, - z - eps), map[m] = i;
}
getline(1, 0, - oo), getline(- 1, 0, 0);
getline(0, - 1, - oo), getline(0, 1, 0);
sort(p + 1, p + m + 1, cmp), l = 1, r = n;
if (okay(r)) printf("%d", r), exit(0);
for (mid = (l + r) >> 1; l < r; mid = (l + r) >> 1)
if (okay(mid)) l = mid + 1; else r = mid;
printf("%d", r - 1);
return 0;
}