您的位置:首页 > 其它

[JZOJ4426]. 【HNOI2016模拟4.4】Stage

2017-07-13 22:26 351 查看

题目大意

给定平面上的 N 个固定的点,以及 M 个以 pi 概率出现的关键点。

问以选出的关键点做出的凸包期望能包含多少个固定的点。

n,m<=1000.

无共线无重点。

分析

我们可以分开一个个点求。即求每个点被凸包包含的概率。

由于:

P(固定点x被包含)=1−P(固定点x不被包含)

P(固定点x不被包含)=P(对所有关键点和x求凸包,x在凸包上)=∑mi=1P(逆时针排列凸包上的点,x和i相连,i是x的下一个点)

如果i是x的下一个点,那么x—>i这条直线两边不能够同时有点出现,如果同时有点,那么肯定和凸包的内角不超过180这一前提条件矛盾。

那么我们只要枚举x,枚举i,算出向量右边的点全部不出现的概率就好了,只用算一边是因为,i是x的下一个点。如果两边都算就变成了,i是x的上一个点或者下一个点,算重了。那一堆全部的点按极角序拍明显在一块儿,那么排极角序搞搞前缀积就好了,注意不要用除法,会有很大精度误差,可以用两个前缀和组合,也可以像我一样用倍增。

代码

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
typedef double db;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
const int N=2005;
struct vec
{
db x,y,p;
vec(db _x=0,db _y=0,db _p=0){x=_x,y=_y,p=_p;}
}a
,b
,c;
db ans,tmp,f
[12],one,two;
int n,m,i,j,k,Log;

int sig(db x)
{
return x>0;
}
vec operator -(vec a,vec b)
{
return vec(a.x-b.x,a.y-b.y,0);
}
db operator ^(vec a,vec b)
{
return a.x*b.y-b.x*a.y;
}
bool operator <(vec a,vec b)
{
return atan2(a.x-c.x,a.y-c.y)<atan2(b.x-c.x,b.y-c.y);
}
void make()
{
int i,j;
fo(i,1,2*m) f[i][0]=1-b[i].p;
fo(j,1,Log)
fo(i,1,2*m-(1<<j)+1)
f[i][j]=f[i][j-1]*f[i+(1<<(j-1))][j-1];
}
db get(int l,int r)
{
int i;
db ret=1;
fd(i,Log,0)
if (l+(1<<i)<=r+1)
{
ret*=f[l][i];
l+=1<<i;
}
return ret;
}
int main()
{
scanf("%d %d",&n,&m);
fo(i,1,n) scanf("%lf %lf",&a[i].x,&a[i].y);
fo(i,1,m) scanf("%lf %lf %lf",&b[i].x,&b[i].y,&b[i].p);
Log=trunc(log((db)2*m)/log(2));
tmp=1;
fo(i,1,m) tmp*=1-b[i].p;
fo(i,1,n)
{
c=a[i];
sort(b+1,b+1+m);
fo(j,1,m/2) swap(b[j],b[m-j+1]);
fo(j,1,m) b[j+m]=b[j];
make();
k=1;
ans+=1;
fo(j,1,m)
{
while ((k<2*m&&((b[j]-c)^(b[k]-c))>=0&&k-j<m)||(k<j)) k++;
ans-=b[j].p*get(k,j+m-1);
}
ans-=get(1,m);
}
printf("%lf\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: