CF几何刷题记录

不开坑就没有方向……
(虽然开了坑也会跑路……)
UPD:退役了退役了,跑路跑路
想把CF里过题人数100+的几何题都做一做……
那就先从1000-往下做吧

模板:

#include<bits/stdc++.h>
#define ERROR 1e99
#define N 100005
using namespace std;
typedef double data;
typedef long long LL;
const data PI=acos(-1.);
const data EPS=1E-10;
int Zero(data O){return fabs(O)<=EPS;}
void Read(data &now){double IO;scanf("%lf",&IO);now=IO;}
struct Point{
	data x,y;
	void read(){Read(x);Read(y);}
	void Print(){printf("%lf %lf\n",(double)x,(double)y);}
	void init(data _x,data _y){x=_x;y=_y;}
	data operator * (const Point &b)const{
		return x*b.y-y*b.x;
	}
	Point operator * (const data &b)const{
		return (Point){x*b,y*b};
	}
	data operator ^ (const Point &b)const{
		return x*b.x+y*b.y;
	}
	Point operator - (const Point &b)const{
		return (Point){x-b.x,y-b.y};
	}
	Point operator + (const Point &b)const{
		return (Point){x+b.x,y+b.y};
	}
	int operator < (const Point &b)const{
		return x<b.x||x==b.x&&y<b.y;
	}
	int operator == (const Point &b)const{
		return Zero(x-b.x)&&Zero(y-b.y);
	}
	void Rotate(data alpha){
		data _x=x*cos(alpha)-y*sin(alpha);
		data _y=y*cos(alpha)+x*sin(alpha);
		x=_x;y=_y;
	}
}ERRORPOINT=(Point){ERROR,ERROR};
struct Line{
	Point p,q;
};
struct Circle{
	Point O;data r;
	void read(){O.read();Read(r);}
};
data sqr(data x){return x*x;}
data dist(Point A,Point B){return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y));}
int Intersection(Line A,Line B,Point &ret){
	ret=A.p;
	data u=(A.p-B.p)*(B.p-B.q);
	data v=(A.p.x-A.q.x)*(B.p.y-B.q.y)-(A.p.y-A.q.y)*(B.p.x-B.q.x);
	if (Zero(v)) return 0;u/=v;
	ret.x+=(A.q.x-A.p.x)*u;
	ret.y+=(A.q.y-A.p.y)*u;
	return 1;
}
int Intersection(Circle C,Line L,Point &A,Point &B){
	Point p=C.O;p.x+=L.p.y-L.q.y;p.y+=L.q.x-L.p.x;
	Intersection((Line){p,C.O},L,p);
	data tmp=sqr(C.r)-sqr(p.x-C.O.x)-sqr(p.y-C.O.y);
	if (tmp<-EPS) return 0;
	data t=sqrt(max(tmp,0.))/dist(L.p,L.q);
	A=p+(L.q-L.p)*t;B=p-(L.q-L.p)*t;
	return 1;
}
int Intersection(Circle C1,Circle C2,Point &A, Point &B) {
	double d = dist(C1.O,C2.O);
	if (d<fabs(C1.r-C2.r)-EPS || d>fabs(C1.r+C2.r)+EPS) return 0;
	double cosa = (sqr(C1.r) + sqr(d) - sqr(C2.r)) / (2 * C1.r * d);
	double sina = sqrt(max(0., 1. - sqr(cosa)));
	A = B = C1.O;
	A.x += C1.r / d * ((C2.O.x - C1.O.x) * cosa + (C2.O.y - C1.O.y) * -sina);
	A.y += C1.r / d * ((C2.O.x - C1.O.x) * sina + (C2.O.y - C1.O.y) * cosa);
	B.x += C1.r / d * ((C2.O.x - C1.O.x) * cosa + (C2.O.y - C1.O.y) * sina);
	B.y += C1.r / d * ((C2.O.x - C1.O.x) *-sina + (C2.O.y - C1.O.y) * cosa);
	return 1;
}

//此处默认data是int 
int Polar_cmp(const Point &A,const Point &B){
	if (A.y==0&&B.y==0) return A.x>0&&B.x<0;
	if (A.y==0) return A.x>0||B.y<0;
	if (B.y==0) return B.x<0&&A.y>0;
	if ((A.y>0)^(B.y>0)) return A.y>0;
	return (A*B)>0;
}

vector<Point>Make_Convex(vector<Point>now){
	sort(now.begin(),now.end());
	if (now.size()<3) return now;
	for (int i=0;i<now.size();i++)
		now[i].Print();
	puts("");
	
	vector<Point>up;up.clear();
	up.push_back(now[0]);
	for (int i=1;i<now.size();i++){
		for (;up.size()>1&&(up[up.size()-2]-up.back())*(now[i]-up.back())<=0;up.pop_back());
		up.push_back(now[i]);
	}
	vector<Point>down;down.clear();
	down.push_back(now.back());
	for (int i=now.size()-1;i>=0;i--){
		for (;down.size()>1&&(down[down.size()-2]-down.back())*(now[i]-down.back())<=0;down.pop_back());
		down.push_back(now[i]);
	}
	
	vector<Point>ret;ret.clear();
	for (int i=down.size()-1;i>0;i--)
		ret.push_back(down[i]);
	for (int i=up.size()-1;i>0;i--)
		ret.push_back(up[i]);
	return ret;
}

//以下是最小圆覆盖

//两个点 
Circle make_2(Point p,Point q){
	Circle ret;
	ret.O.x=(p.x+q.x)/2.0;
	ret.O.y=(p.y+q.y)/2.0;
	ret.r=dist(ret.O,p);
	return ret;
}
//返回三角形的外心  
Circle make_3(const Point &a,const Point &b,const Point &c)  {
    data a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2;  
    data a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2;  
    data d=a1*b2-a2*b1;
    Circle ret;
    ret.O.x=a.x+(c1*b2-c2*b1)/d;
    ret.O.y=a.y+(a1*c2-a2*c1)/d;
    ret.r=dist(ret.O,a);
    return ret;
} 
bool IN(Circle now,Point a){
	return (dist(now.O,a)<=now.r+EPS);
}
Circle Smallest_Circle(Point *a,int n){
	if (n==1) return (Circle){a[1],0};
	srand(2333);
	random_shuffle(a+1,a+n+1);
	Circle cur=make_2(a[1],a[2]);
	for (int i=2;i<=n;i++)
		if (!IN(cur,a[i])){
			cur=make_2(a[1],a[i]);
			for (int j=1;j<i;j++)
				if (!IN(cur,a[j])){
					cur=make_2(a[i],a[j]);
					for (int k=1;k<j;k++)
						if (!IN(cur,a[k]))
							cur=make_3(a[i],a[j],a[k]);
				}
		}
	return cur;
}
int main(){
}

【280A】
   有一个水平放置的长方形。求它绕中心旋转\(\alpha\)度后的图形与原图形的面积交。
   直接分类讨论感觉很烦烦。本来想趁机搞一个HPI的板子,可是放弃了……
   后来用了一个比较巧妙的做法。把两个矩形的边框拿来交一交,只有都在两条直线内的交点才会是最终答案凸包上的点。然后随便做个凸包就好了。

【793C】
   有一坨给定初始坐标和方向向量的点,还有一个固定的矩形。问一个最早的时刻,使得所有点都严格在矩形内部。
   因为是矩形,把直线画出来后,最多只会与矩形交两个unique的点(注意到<2必然是无解)。然后算一算对应时间求个交即可。
   此题最大的坑点是“严格”。最后的合法区间如果只有一个值,那么其实是不合法的;这个eps就很耐人寻味。还要注意那些和边框重合的运动路线也是不合法的。

【166B】
   分析一下题目性质,转化为问一个点是否严格在一个凸包内部。
   分别维护出上凸壳和下凸壳,每次二分后用叉积判断即可。

【600D】
   求两个圆面积交……看起来很old,确是一道特别帅气的题……
   其实就是求两个弓形的面积。我本来是直接求交点,用叉积计算三角形面积,然后余弦定理算一下扇形的角度。
   但是数据范围太大了,求交的精度会爆炸……
   其实知道了半径和距离后,换个三角形研究,即可算出扇形的角度……然后根据角度再计算三角形。
   仔细想想,这也能开发出求交的另一个方法。虽然有三角函数,但感觉精度靠谱很多。

【2C】
   对于其中两个圆,可以发现符合要求的点在一条直线或者一个圆上。
   那么最终答案就在圆/直线与圆/直线的交点上。检验板子的好题……

posted @ 2018-02-21 10:25  了491  阅读(608)  评论(0编辑  收藏  举报