题目描述
沫沫最近在玩一个二维的射箭游戏,如下图 1 所示,这个游戏中的 x 轴在地面,第一象限中有一些竖直线段作为靶子,任意两个靶子都没有公共部分,也不会接触坐标轴。
沫沫控制一个位于(0,0)的弓箭手,可以朝 0 至 90?中的任意角度(不包括 0度和 90度),以任意大小的力量射出带有穿透能力的光之箭。由于游戏中没有空气阻力,并且光之箭没有箭身,箭的轨迹会是一条标准的抛物线,被轨迹穿过的所有靶子都认为被沫沫射中了,包括那些 只有端点被射中的靶子。
这个游戏有多种模式,其中沫沫最喜欢的是闯关模式。
在闯关模式中,第一关只有一个靶 子,射中这个靶子即可进入第二关,这时在第一关的基础上会出现另外一个靶子,若能够一箭 双雕射中这两个靶子便可进入第三关,这时会出现第三个靶子。依此类推,每过一关都会新出 现一个靶子,在第 K 关必须一箭射中前 K 关出现的所有 K 个靶子才能进入第 K+1 关,否则游戏 结束。
沫沫花了很多时间在这个游戏上,却最多只能玩到第七关”七星连珠“,这让她非常困惑。 于是她设法获得了每一关出现的靶子的位置,想让你告诉她,最多能通过多少关
输入输出格式
输入格式:
输入文件第一行是一个正整数N,表示一共有N关。接下来有N行,第i+1行是用空格隔开的三个正整数xi,yi1,yi2(yi1<yi2 ),表示第i关出现的靶子的横坐标是xi,纵坐标的范围是从yi1到yi2 。 输入保证30%的数据满足N<=100,50%的数据满足N<=5000,100%的数据满足N<=100000且给 出的所有坐标不超过109 。
输出格式:
仅包含一个整数,表示最多的通关数。
输入输出样例
输入样例#1:
5
2 8 12
5 4 5
3 8 10
6 2 3
1 3 7
输出样例#1:
3
题解
对于每个限制((x1,y1),(x2,y2))需要满足
(ax1^2+bx1>=y1\ax2^2+bx2<=y2)
然后可以看做是(ax1+b>=frac{y1}{x1}\ax2+b<=frac{y2}{x2})
移一下项(b>=frac{y1}{x1}-ax1\b<=frac{y2}{x2}-ax2)
然后就可以把每个限制想成两条直线,把(b)作为坐标轴
做半平面交即可
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define double long double
const int M = 300050 ;
const double INF = 1e18 ;
const double EPS = 1e-19 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
int n , cnt ;
inline int sgn(double x) {
if(fabs(x) < EPS) return 0 ;
return x > 0 ? 1 : -1 ;
}
struct Vec {
double x , y ;
Vec (double Tx = 0 , double Ty = 0) {
x = Tx , y = Ty ;
}
} p[M] ;
inline Vec operator + (Vec A , Vec B) {
return (Vec) { A.x + B.x , A.y + B.y } ;
}
inline Vec operator - (Vec A , Vec B) {
return (Vec) { A.x - B.x , A.y - B.y } ;
}
inline Vec operator * (Vec A , double B) {
return (Vec) { A.x * B , A.y * B } ;
}
inline Vec operator / (Vec A , double B) {
return (Vec) { A.x / B , A.y / B } ;
}
struct Line {
int id ;
Vec s , t , v ; double Ang ;
Line () { } ;
Line (int idt , Vec A , Vec B) {
id = idt ; s = A ; t = B ;
v = t - s ; Ang = atan2(v.y , v.x) ;
}
} l[M] , que[M] ;
inline double Dot(Vec A , Vec B) {
return A.x * B.x + A.y * B.y ;
}
inline double Cross(Vec A , Vec B) {
return A.x * B.y - A.y * B.x ;
}
inline bool operator < (Line A , Line B) {
if(sgn(A.Ang - B.Ang) != 0) return A.Ang < B.Ang ;
else return sgn(Cross(A.v , B.s - A.s)) < 0 ;
}
inline bool Is_para(Line A , Line B) {
return sgn(Cross(A.v , B.v)) == 0 ;
}
inline bool OnRight(Vec P , Line L) {
return sgn(Cross(P - L.s , L.v)) > 0 ;
}
inline Vec GLI(Line A , Line B) {
Vec c = B.s - A.s ;
double t = Cross(B.v , c) / Cross(B.v , A.v) ;
return A.s + A.v * t ;
}
inline bool check(int mid) {
int i = 1 , head = 1 , tail = 1 ;
while(l[i].id > mid)
++ i ;
que[tail] = l[i] ;
for(++ i ; i <= cnt ; i ++) {
if(l[i].id > mid) continue ;
if(head < tail && (Is_para(que[head] , que[head + 1]) || Is_para(que[tail - 1] , que[tail])))
return false ;
while(head < tail && OnRight(p[tail - 1] , l[i])) -- tail ;
while(head < tail && OnRight(p[head] , l[i])) ++ head ;
if(sgn(que[tail].Ang - l[i].Ang)) que[++tail] = l[i] ;
else continue ;
if(head < tail) p[tail - 1] = GLI(que[tail] , que[tail - 1]) ;
}
while(head < tail && OnRight(p[tail - 1] , que[head])) -- tail ;
while(head < tail && OnRight(p[head] , que[tail])) ++ head ;
if(tail - head <= 1) return false ;
return true ;
}
int main() {
n = read() ;
for(int i = 1 , x , yf , ys ; i <= n ; i ++) {
x = read() ; yf = read() ; ys = read() ;
Vec p1 = Vec (0.0 , (double)yf / x) ; Vec p2 = Vec (1.0 , (double)yf / x - x) ;
Vec p3 = Vec (1.0 , (double)ys / x - x) ; Vec p4 = Vec (0.0 , (double)ys / x) ;
l[++cnt] = Line ( i , p1 , p2 ) ; l[++cnt] = Line ( i , p3 , p4 ) ;
}
l[++cnt] = Line ( 0 , Vec(-INF , EPS) , Vec(-EPS , EPS) ) ;
l[++cnt] = Line ( 0 , Vec(-EPS , EPS) , Vec(-EPS , INF) ) ;
l[++cnt] = Line ( 0 , Vec(-EPS , INF) , Vec(-INF , INF) ) ;
l[++cnt] = Line ( 0 , Vec(-INF , INF) , Vec(-INF , EPS) ) ;
sort(l + 1 , l + cnt + 1) ;
int l = 1 , r = n , ret = 0 ;
while(l <= r) {
int mid = (l + r) >> 1 ;
if(check(mid)) l = mid + 1 , ret = mid ;
else r = mid - 1 ;
}
printf("%d
",ret) ;
return 0 ;
}