洛谷3222 [HNOI2012]射箭 (半平面交)

qwq自闭
第一次见到卡精度卡成这样 细节卡到这样的题
qwq

首先,对于这个题,一个比较容易想到的东西就是二分最后的答案,然后去 c h e c k check ,但是check的时候qwq 我就wei掉了

换一种方法考虑,我们对于每一关的要求,实际上要满足的是找到一组 ( a , b ) (a,b) 满足 y 1 a x 2 + b y 2 y1\le ax^2+b\le y2

y 1 x a x + b y 2 x \frac{y1}{x} \le ax+b\le \frac{y2}{x}

那么我们把 x x 看成一个常数系数的话,实际上这就转化成了一个直线的半平面交的问题
我们要求两个直线满足
y 1 x a x b \frac{y1}{x} - ax \le b

b y 2 x a x b\le \frac{y2}{x}- ax

注意直线的方向,应该是相反的两个方向的直线。

但是实际上这个题还是有很多的坑点

1. e p s eps 要开到 1 e 16 1e-16%

2.抛物线只能开口向下
3.抛物线不能是直线
4.要注意一个点的半平面交,以及要开 l o n g   d o u b l e long \ double

反正就是很自闭了
qwq

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
#define ld long double
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
const int maxn = 1e6+1e2;
const ld eps = 1e-18;
const ld pai = acos(-1);
const ld inf = 1e15+1;
int dcmp(ld x)
{
	if (x>eps) return 1;
	if (x<-eps) return -1;
	return 0;
}
struct Point
{
   ld x,y;	
};
Point operator + (Point a,Point b)
{
	return (Point){a.x+b.x,a.y+b.y};
}
Point operator - (Point a,Point b)
{
	return (Point){a.x-b.x,a.y-b.y};
}
Point operator * (Point a,ld b)
{
	return (Point){a.x*b,a.y*b};
}
Point operator / (Point a,ld b)
{
	return (Point){a.x/b,a.y/b};
}
struct Line
{
	Point x,y;
	ld ang;
	int num;
};
Line ccount(Point x,Point y,int oo)
{
	Point now = y-x;
	Line a;
	a.x=x;
	a.y=y;
	a.ang = atan2(now.y,now.x);
	a.num = oo;
	return a;
}
ld diancheng(Point x,Point y)
{
	return x.x*y.x+x.y*y.y;
}
ld chacheng(Point x,Point y)
{
	return x.x*y.y-x.y*y.x;
}
bool pingxing(Line a,Line b)
{
	return dcmp(chacheng(a.y-a.x,b.y-b.x))==0;
}
bool isright(Line a,Point b)
{
	return dcmp(chacheng(a.y-a.x,b-a.x))==-1;
}
Point jiaodian(Line a,Line b)
{
	return a.x+(a.y-a.x) * (chacheng(b.y-b.x,a.x-b.x)/chacheng(a.y-a.x,b.y-b.x));
}
bool operator <(Line a,Line b)
{
	ld now = a.ang-b.ang;
	if (dcmp(now)!=0)
	{
		if (dcmp(now)==-1) return 1;
		else return 0; 
	}
	else
	{
		ld tmp = chacheng(a.y-a.x,b.y-a.x);
		if (dcmp(tmp)==-1) return 1;
		else return 0; 
	}
}
int n,m;
Line l[maxn];
Line qx[maxn];
Point qd[maxn];
int num;
Line ymh[maxn];
bool solve(int n)
{
	int head=0,tail=1;
	qx[++head]=l[1];
	for (int i=2;i<=n;i++)
	{
		if (dcmp(l[i].ang-l[i-1].ang)==0) continue;
		if (head<tail && (pingxing(qx[head],qx[head+1]) || pingxing(qx[tail],qx[tail-1]))) return false;
		while (head<tail &&isright(l[i],qd[tail-1])) tail--;
		while (head<tail && isright(l[i],qd[head])) head++;
		qx[++tail]=l[i];
		if (head<tail) qd[tail-1]=jiaodian(qx[tail],qx[tail-1]);
	} 
	while (head<tail && isright(qx[head],qd[tail-1])) tail--;
	while (head<tail && isright(qx[tail],qd[head])) head++;
	if (tail-head+1<=2) return false;
	qd[tail]=jiaodian(qx[head],qx[tail]);
	int tmp=0;
	for (int i=head;i<=tail;i++) if (qd[i].x<0) tmp++;
	if (tmp==0) return false;
	return true;
}
bool check(int mid)
{
	int num=0;
	for (int i=1;i<=n;i++)
	{
		if (ymh[i].num<=mid) l[++num]=ymh[i];
	}
	return solve(num);
}
int main()
{
  m=read();
  for (int i=1;i<=m;i++)
  {
  	long double x,y,z;
  	scanf("%Lf%Lf%Lf",&x,&y,&z);
  	Point xx = (Point){0,y/x};
  	Point yy = (Point){1,y/x-x};
    Point xxx = (Point){0,z/x};
  	Point yyy = (Point){1,z/x-x};
  	int ii=i;
  	++n;
  	ymh[n]=ccount(xx,yy,ii);
	ymh[n].num=i;
	++n;
	ymh[n]=ccount(yyy,xxx,ii);
	ymh[n].num=i;
  }
  Point a = (Point){-inf,eps};
  Point b = (Point){inf,eps};
  Point c = (Point){inf,inf};
  Point d = (Point){-inf,inf};
  ymh[++n]=ccount(a,b,0);
  ymh[++n]=ccount(b,c,0);
  ymh[++n]=ccount(c,d,0);
  ymh[++n]=ccount(d,a,0);
  sort(ymh+1,ymh+1+n); 
  int l=0,r=m;
  int ans=0;
  while(l<=r)
  {
  	int mid = l+r >> 1;
  	if (check(mid)) ans=mid,l=mid+1;
  	else r=mid-1;
  } 
  cout<<ans;
  return 0;
}

猜你喜欢

转载自blog.csdn.net/y752742355/article/details/87253853
今日推荐