[JZOJ4426]. 【HNOI2016模拟4.4】Stage

来源:互联网 发布:软件测试实践报告 编辑:程序博客网 时间:2024/05/17 01:32

题目大意

给定平面上的 N 个固定的点,以及 M 个以 pi 概率出现的关键点。
问以选出的关键点做出的凸包期望能包含多少个固定的点。
n,m<=1000.
无共线无重点。

分析

我们可以分开一个个点求。即求每个点被凸包包含的概率。
由于:
P(x)=1P(x)
P(x)=P(xx)=mi=1P(xiix)
如果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[N],b[N],c;db ans,tmp,f[N][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);}