洛谷P4502 [ZJOI2018]保镖(计算几何+三维凸包)
题面
题解
我对计蒜几盒一无所知
顺便\(xzy\)巨巨好强
前置芝士
三维凸包
啥?你不会三维凸包?快去把板子写了->这里
欧拉公式
\]
\(V:vertex\)顶点,\(E:edge\)边,\(F:flat\)面,对所有维度的所有多边形(多面体)都成立
圆的反演
设反演中心为\(O\),常数为\(k\),若经过\(O\)的直线经过\(P,P'\),且\(OP\times OP'=k\),则称\(P,P'\)关于\(O\)互为反演,其中\(O\)为反演中心,\(k\)为反演幂
\(Voronoi\)图
又称泰森多边形,即划分一个平面,把每个平面划分到离它最近的点那里
\(Delaunay\)三角剖分
差不多就是类似于
不难发现,\(Voronoi\)图和\(Delaunay\)三角剖分互为对偶图
而且\(Delaunay\)三角剖分有一些奇特的性质
定理:三角形个数和和外围凸包上的点数之和为\(2n-2\)
用欧拉公式来证明,我们可以把这个三角剖分看成一个多面体,其中每一个三角形都是它的一个面,凸包上的所有点构成了底面,那么三角形个数就是\(F-1\)。设凸包上的点的个数为\(k\),那么有
\]
化简之后发现有\(k+F-1=2n-2\)
顺带一提这个公式对所有的三角剖分都适用
定理:平面上的点集有唯一的\(Delaunay\)三角剖分(因为泰森多边形的每一个交点都属于三个顶点。唯一的例外就是存在四点共圆的时候,此时这个性质不成立)
定理:任意一个\(Delaunay\)三角形的外接圆不包含点集中的其他点。(称为\(Delaunay\)三角形的空圆性质)
\(First\)
凸包点数具有整体性,很难求,那么我们就可把它转化为求\(Delaunay\)三角形的期望个数
每一个\(Delaunay\)三角形都对应一个外接圆,我们称之为\(Delaunay\)圆,那么又变成数\(Delaunay\)圆的期望个数,设为\(k\),那么答案就是\(2n-2-k\)
我们定义支配圆为包含点集中所有点的圆,因为\(Delaunay\)圆不包含除了\(Delaunay\)三角形之外的任何一个点,所以有以下结论
定理:对于\(Delaunay\)圆,如果反演中心在这个圆中,那么在反演之后的图形中这个圆是支配圆,否则这个圆仍然是\(Delaunay\)圆
定理:对于支配圆,如果反演中心在这个圆中,那么在反演之后的图形中这个圆是\(Delaunay\)圆,否则它仍为支配圆
证明我不会,感性理解一下好了
那么题目就可以转化为求原图中\(Delaunay\)圆的个数\(\times\)反演中心在圆内的概率\(+\)支配圆的个数$\times \(反演中心在圆外的概率,我们设为\)E$
只要用\(Delaunay\)圆的总数加上支配圆的总数减去\(E\)就可以求得\(Delaunay\)三角形的期望个数了
\(Second\)
我们考虑一个圆的方程
\]
如果我们设一个三维上的平面方程,为
\]
那么点\((x,y)\)在圆上当且仅当\(z=x^2+y^2\)
所以我们可以把一个点\((x,y)\)投影到三维坐标系中,新的坐标设为\((x,y,x^2+y^2)\)。那么对于一个圆对应的平面\(z+Dx+Ey+F=0\)来说,如果一个点的坐标在这个平面上,那么这个点在这个圆上。同时也能发现如果点的坐标在平面下方,这个点在圆内,如果点的坐标在平面上方,这个点在圆外
那么我们对于所有的这个三维空间内的所有的点求一个凸包,然后我们发现,不过是\(Delaunay\)圆还是支配圆,它们对应的平面都只会在这个凸包的表面上
更进一步,我们发现下凸壳上的每一个平面都对应一个\(Delaunay\)圆,上凸壳上的每一个平面都对应一个支配圆
因为这\(n\)个顶点每个点都至少是一个\(Delaunay\)圆的顶点,所以每一个点都会存在于这个凸包中,那么这个凸包的点数就是\(n\),根据三维凸包里我们的计算,此时\(F=2n-4\),即面数为\(2n-4\),\(Delaunay\)圆的总数加上支配圆的总数就是\(2n-4\)
所以最终的答案可以表示成\(Ans=2n-2-(2n-4-E)=2+E\)
综上
我们读入所有点之后随机扰动来防止四点共圆和三维凸包中四点共面的情况。求出三维凸包之后,对于每个面,求出其对应的三个点的外接圆,如果是上凸面,则其为支配圆,只有在反演中心在圆内的时候才有贡献。如果是下凸面,则其为\(Delaunay\)圆,只有在反演中心在圆外时才有贡献。只要求出矩形和圆的交的面积就行了
然后兴高采烈地交上去发现精度爆炸只有\(60\)分
于是你需要一个叫做\(\_\_float128\)的黑科技
然后没有然后了
吉司机怕是根本没打算给部分分
//minamoto
#include<bits/stdc++.h>
#define R register
#define db __float128
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=2005;const db eps=1e-10;
inline db Rd(){return 1.0*rand()/RAND_MAX;}
inline db reps(){return (Rd()-0.5)*eps;}
inline int dcmp(const R db &x){return x<-eps?-1:x>eps?1:0;}
struct point{
db x,y;
point(){}
point(R db xx,R db yy):x(xx),y(yy){}
inline point operator -(const point &b)const{return point(x-b.x,y-b.y);}
inline point operator +(const point &b)const{return point(x+b.x,y+b.y);}
inline point operator *(const db &b)const{return point(x*b,y*b);}
inline point operator /(const db &b)const{return point(x/b,y/b);}
inline db operator *(const point &b)const{return x*b.y-y*b.x;}
inline db operator ^(const point &b)const{return x*b.x+y*b.y;}
inline db len(){return sqrt((double)(x*x+y*y));}
inline db len2(){return x*x+y*y;}
inline void rot(){R db t=x;x=-y,y=t;}
}qwq[4];
struct node{
db x,y,z;
node(){}
node(R db xx,R db yy,R db zz):x(xx),y(yy),z(zz){}
inline void shake(){x+=reps(),y+=reps(),z+=reps();}
inline node operator -(const node &b)const{return node(x-b.x,y-b.y,z-b.z);}
inline node operator *(const node &b)const{return node(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);}
inline db operator ^(const node &b)const{return x*b.x+y*b.y+z*b.z;}
}p[N];
struct Flat{
int id[3];
Flat(){}
Flat(R int x,R int y,R int z){id[0]=x,id[1]=y,id[2]=z;}
inline node normal(){return (p[id[1]]-p[id[0]])*(p[id[2]]-p[id[0]]);}
inline bool ck(const node &b){return ((b-p[id[0]])^normal())>0;}
}f[8005];
int n,cnt,x,y;
namespace Convex{
bool vis[N][N];Flat st[8005];int top,v;
void MAIN(){
fp(i,1,n)p[i].shake();
f[++cnt]=Flat(1,2,3),f[++cnt]=Flat(3,2,1);
fp(i,4,n){
top=0;
fp(j,1,cnt){
v=f[j].ck(p[i]),!v?(st[++top]=f[j],0):0;
vis[f[j].id[0]][f[j].id[1]]=
vis[f[j].id[1]][f[j].id[2]]=
vis[f[j].id[2]][f[j].id[0]]=v;
}
fp(j,1,cnt){
if(vis[f[j].id[0]][f[j].id[1]]&&!vis[f[j].id[1]][f[j].id[0]])st[++top]=Flat(i,f[j].id[0],f[j].id[1]);
if(vis[f[j].id[1]][f[j].id[2]]&&!vis[f[j].id[2]][f[j].id[1]])st[++top]=Flat(i,f[j].id[1],f[j].id[2]);
if(vis[f[j].id[2]][f[j].id[0]]&&!vis[f[j].id[0]][f[j].id[2]])st[++top]=Flat(i,f[j].id[2],f[j].id[0]);
}
fp(j,1,top)f[j]=st[j];cnt=top;
}
}
}
namespace Area{
point cross(R point a1,R point a2,R point b1,R point b2){
R point a=a2-a1,b=b2-b1,c=b1-a1;
R db t=(b*c)/(b*a);
return a1+a*t;
}
inline db rad(const R point &p1,const R point &p2){return atan2((double)(p1*p2),(double)(p1^p2));}
//这里计算角度有方向,表示p2顺时针旋转多少度到p1
db calc(R db r,R point p1,R point p2){
R point e=(p1-p2)/(p1-p2).len(),ee=e;e.rot();
R point mid=cross(p1,p2,point(0,0),e);
if(mid.len()>=r)return r*r*rad(p1,p2)/2;
R db d=sqrt((double)(r*r-mid.len2()));
R point w1=mid+ee*d,w2=mid-ee*d;
R int b1=(dcmp(p1.len2()-r*r)>0),b2=(dcmp(p2.len2()-r*r)>0);
if(b1&&b2){
if(dcmp((p1-mid)^(p2-mid))<=0)return r*r*(rad(w2,p2)+rad(p1,w1))/2+w1*w2/2;
return r*r*rad(p1,p2)/2;
}
if(b1)return (r*r*rad(p1,w1)+w1*p2)/2;
if(b2)return (r*r*rad(w2,p2)+p1*w2)/2;
return p1*p2/2;
}
db ins(R point O,R db r){
return calc(r,qwq[0]-O,qwq[1]-O)
+calc(r,qwq[1]-O,qwq[2]-O)
+calc(r,qwq[2]-O,qwq[3]-O)
+calc(r,qwq[3]-O,qwq[0]-O);
}
}
namespace loli{
db s,res,r;
point a1,a2,b1,b2,c,d,O;
void MAIN(){
n=read(),x=read(),y=read(),qwq[0]=point(x,y);
qwq[1].y=y,qwq[3].x=x;
x=read(),y=read(),qwq[2]=point(x,y);
qwq[1].x=x,qwq[3].y=y;
s=(qwq[2].x-qwq[0].x)*(qwq[2].y-qwq[0].y),res=0;
fp(i,1,n)x=read(),y=read(),p[i]=node(x,y,1.0*x*x+1.0*y*y);
Convex::MAIN();
fp(i,1,cnt){
a1=point(p[f[i].id[0]].x,p[f[i].id[0]].y),
a2=point(p[f[i].id[1]].x,p[f[i].id[1]].y),
c=(a1+a2)/2,d=a2-a1,d.rot(),a1=c,a2=c+d,
b1=point(p[f[i].id[1]].x,p[f[i].id[1]].y),
b2=point(p[f[i].id[2]].x,p[f[i].id[2]].y),
c=(b1+b2)/2,d=b2-b1,d.rot(),b1=c,b2=c+d,
O=Area::cross(a1,a2,b1,b2),
d=point(p[f[i].id[0]].x,p[f[i].id[0]].y),
r=(O-d).len();
f[i].normal().z>0?res+=s-Area::ins(O,r):res+=Area::ins(O,r);
}
printf("%.11lf\n",(double)(res/s+2));
}
}
int main(){
srand(19260817);
// freopen("testdata.in","r",stdin);
loli::MAIN();
return 0;
}
洛谷P4502 [ZJOI2018]保镖(计算几何+三维凸包)的更多相关文章
- 题解-洛谷P4724 【模板】三维凸包
洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...
- 洛谷P4724 【模板】三维凸包
题面 传送门 题解 先理一下关于立体几何的基本芝士好了--顺便全都是从\(xzy\)巨巨的博客上抄来的 加减 三维向量加减和二维向量一样 模长 \(|a|=\sqrt{x^2+y^2+z^2}\) 点 ...
- 洛谷P3810 陌上花开 CDQ分治(三维偏序)
好,这是一道三维偏序的模板题 当然没那么简单..... 首先谴责洛谷一下:可怜的陌上花开的题面被无情的消灭了: 这么好听的名字#(滑稽) 那么我们看了题面后就发现:这就是一个三维偏序.只不过ans不加 ...
- 【算法学习】【洛谷】cdq分治 & P3810 三维偏序
cdq是何许人也?请参看这篇:https://wenku.baidu.com/view/3b913556fd0a79563d1e7245.html. 在这篇论文中,cdq提出了对修改/询问型问题(Mo ...
- 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)
洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...
- 洛谷 P3810 【模板】三维偏序(陌上花开) (cdq分治模板)
在solve(L,R)中,需要先分治solve两个子区间,再计算左边区间修改对右边区间询问的贡献. 注意,计算额外的贡献时,两子区间各自内部的顺序变得不再重要(不管怎么样左边区间的都发生在右边之前), ...
- 洛谷P4337 [ZJOI2018]线图(状压+搜索+乱搞)
题面 传送门 题解 妈呀调了我整整一天-- 题解太长了不写了可以去看\(shadowice\)巨巨的 //minamoto #include<bits/stdc++.h> #define ...
- [洛谷P3810]【模板】三维偏序(陌上花开)
题目大意:有$n$个元素,第$i$个元素有三个属性$a_i,b_i,c_i$,设$f(i)=\sum\limits_{i\not = j}[a_j\leqslant a_i,b_j\leqslant ...
- 洛谷CF1071E Rain Protection(计算几何,闵可夫斯基和,凸包,二分答案)
洛谷题目传送门 CF题目传送门 对于这题,我无力吐槽. 虽然式子还是不难想,做法也随便口胡,但是一些鬼畜边界情况就是判不对. 首先显然二分答案. 对于每一个雨滴,它出现的时刻我们的绳子必须落在它上面. ...
随机推荐
- js 鼠标点击文本框 提示文字消失
onfocus="if(this.value==defaultValue) {this.value='';}" onblur="if(!value) {value=def ...
- scikit-learn和tensorflow的区别
1.功能不同 Scikit-learn(sklearn)的定位是通用机器学习库,而TensorFlow(tf)的定位主要是深度学习库.一个显而易见的不同:tf并未提供sklearn那种强大的特征工程, ...
- IDEA实用的第三方插件和工具介绍设置
一:grep console grep-console插件可以让idea显示多颜色调试日志,使Log4j配置输出的不同级别error warn info debug fatal显示不同颜色 开发起来区 ...
- leetcode728
vector<int> selfDividingNumbers(int left, int right) { vector<int> V; for (int i = left; ...
- 前端工作准备-foxmail登陆失败汇总
foxmail 管理邮箱账号的一个工具软件, 但是在登陆的时候总是遇到明明账号密码没有问题,却总是报错,这里我登陆的时候的集中解决方法总结下: pop和imap 是邮箱的两种协议,大多选imap协议, ...
- Eclipse 代码风格配置
代码风格配置:
- 解决free -h cached 过大 问题
//先同步数据 sync //cache 释放: //To free pagecache: echo 1 > /proc/sys/vm/drop_caches //To free dentrie ...
- JBPM具体应用之decision节点的使用
JBPM工作流引擎为我们提供了许多的节点应用,每一个节点都有其不同的作用,其中有四个比较常用的节点,他们分别decision,fork,state和task.在本文中我们先介绍decision节点,余 ...
- 【原】Coursera—Andrew Ng机器学习—Week 2 习题—Linear Regression with Multiple Variables 多变量线性回归
Gradient Descent for Multiple Variables [1]多变量线性模型 代价函数 Answer:AB [2]Feature Scaling 特征缩放 Answer:D ...
- webmagic使用
webmagic是Java语言用于爬虫的工具.官网地址:http://webmagic.io/,中文文档地址:http://webmagic.io/docs/zh/ 使用webmagic有3种配置需要 ...