[HNOI2012]射箭

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HNOI2012]射箭相关的知识,希望对你有一定的参考价值。

射箭

题解

首先,我们的抛物线一定是可以被表示成 y = a x 2 + b x ( a < 0 , b > 0 ) y=ax^2+bx(a<0,b>0) y=ax2+bx(a<0,b>0),因为这是一个在第一象限的开口向下的抛物线。
显然,这里我们的未知数有两个 a , b a,b a,b,我们要求的是调整二元组 ( a , b ) (a,b) (a,b)使只经过更多的线段。
由于我们的线段都是 ( x 0 , y 1 ) − > ( x 0 , y 2 ) (x_0,y_1)->(x_0,y_2) (x0,y1)>(x0,y2)形式的,所以我们经过该条线段必然满足
y 1 ⩽ a x 2 + b x ⩽ y 2 ⇒ k 1 ⩽ a x + b ⩽ k 2 y_1\\leqslant ax^2+bx\\leqslant y_2\\Rightarrow k_1\\leqslant ax+b\\leqslant k_2 y1ax2+bxy2k1ax+bk2也就是说,我们的 a x + b ax+b ax+b的范围是固定的。
我们将 ( a , b ) (a,b) (a,b)看成点, x 0 x_0 x0看成斜率,那么相当于我们的 ( a , b ) (a,b) (a,b)要在 y = x 0 x − k 1 y=x_0x-k_1 y=x0xk1 y = x 0 x − k 2 y=x_0x-k_2 y=x0xk2之间。
我们可以去二分我们的通关数,再判断是否存在这样的 ( a , b ) (a,b) (a,b)可以通关这么多关。
判断是否存在这样的点就是一个半平面交的过程,我们先将所有线段都排好序,再从中选择要用的线段,看有么有交就可以了。

时间复杂度 O ( n log ⁡   n ) O\\left(n\\log\\,n\\right) O(nlogn)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXM (1<<18)+5
#define MAXN 500005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double ld;
typedef pair<int,int> pii;
const double INF=1e12;
const int mo=1e9+1;
const int inv2=5e8+4;
const int jzm=233333333;
const int zero=100;
const int lim=1000000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-12;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0')if(s=='-')f=-1;s=getchar();
	while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
	x*=f;

template<typename _T>
void print(_T x)if(x<0)x=(~x)+1;putchar('-');if(x>9)print(x/10);putchar(x%10+'0');
int gcd(int a,int b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;return t;
double sqr(double x)return x*x;
struct point
	double x,y;point()x=y=0;
	point(double X,double Y)x=X;y=Y;
	point operator + (const point &rhs)constreturn point(x+rhs.x,y+rhs.y);
	point operator - (const point &rhs)constreturn point(x-rhs.x,y-rhs.y);
	double operator * (const point &rhs)constreturn x*rhs.x+y*rhs.y;
	double operator ^ (const point &rhs)constreturn x*rhs.y-y*rhs.x;
	point operator * (const double &rhs)constreturn point(x*rhs,y*rhs);
	point operator / (const double &rhs)constreturn point(x/rhs,y/rhs);
	bool operator == (const point &rhs)constreturn Fabs(x-rhs.x)<eps&&Fabs(y-rhs.y)<eps;
	bool operator != (const point &rhs)constreturn Fabs(x-rhs.x)>eps||Fabs(y-rhs.y)>eps;
	bool operator < (const point &rhs)constreturn Fabs(y-rhs.y)<eps?x<rhs.x:y<rhs.y; 
	double length()return sqrt(sqr(x)+sqr(y));
	point rev()return point(y,-x);
p[MAXN];
double dist(point x,point y)return (x-y).length();
struct line
	point s,t,v;double ag;int id;line()
	line(point S,point T,int I)s=S;t=T;v=t-s;ag=atan2(v.y,v.x);id=I;
	double slope()return v.y/v.x;
	double length()return dist(s,t);
	bool operator < (const line &rhs)constreturn ag<rhs.ag;
	bool judge(point rhs)return (v^(rhs-s))<-eps;
a[MAXN],q[MAXN];
int work(double x)if(Fabs(x)<eps)return 0;return x>0?1:-1;
bool LineCross(line x,line y)return work((x. s-y.s)^(x.t-y.s))*work((x.s-y.t)^(x.t-y.t))<=0;
point askCross(line x,line y)return x.s+x.v*((y.v^(y.s-x.s))/(y.v^x.v));
int n,tot;
bool check(int mid)
	int head=0,tail=0;
	for(int i=1;i<=tot;i++)
		if(a[i].id>mid)continue;bool ff=0;
		if(head==tail)q[tail++]=a[i];continue;
		while(head+1<tail&&a[i].judge(p[tail-2]))tail--;
		while(head+1<tail&&a[i].judge(p[head]))head++;
		if(a[i].ag!=q[tail-1].ag)q[tail++]=a[i];if(ff)puts("first");
		else if(a[i].judge(q[tail-1].s))q[tail-1]以上是关于[HNOI2012]射箭的主要内容,如果未能解决你的问题,请参考以下文章

[HNOI2012]射箭

BZOJ 2732: [HNOI2012]射箭

BZOJ2732:[HNOI2012]射箭——题解

[HNOI2012]射箭

[bzoj2732][HNOI2012]射箭

bzoj2732[HNOI2012]射箭 二分+半平面交