[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
y1⩽ax2+bx⩽y2⇒k1⩽ax+b⩽k2也就是说,我们的
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=x0x−k1与
y
=
x
0
x
−
k
2
y=x_0x-k_2
y=x0x−k2之间。
我们可以去二分我们的通关数,再判断是否存在这样的
(
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]射箭的主要内容,如果未能解决你的问题,请参考以下文章