[BZOJ1132][POI2008]Tro(计算几何)

来源:互联网 发布:淘宝买装饰画 编辑:程序博客网 时间:2024/05/16 14:05

题目描述

传送门

题目大意:平面上有N个点. 求出所有以这N个点为顶点的三角形的面积和。

题解

枚举每一个点,以它为原点建立平面直角坐标系,然后其他的点按照极角排序。
向量的叉积满足分配律,所以可以two pointer一下,每一次右指针移动到最后一个与左指针夹角小于180°的地方,然后每加入一个向量,计算一下这个向量与两个指针之间所有向量的叉积,利用分配律。
看了PoPoQQQ的题解才发现,其实不用这么麻烦,可以将第一、四象限和x、y轴正半轴上的点按照极角排序,然后维护一个前缀和
原来是用了愚蠢的方法死慢死慢
不过这题还卡精度,建议全程int/long long,最后先*10再手动除

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 6005const double pi=acos(-1.0);struct Vector{    int x,y;    double ang;    Vector(int X=0,int Y=0)    {        x=X,y=Y;        ang=atan2((double)y,(double)x);    }    bool operator < (const Vector &a) const    {        return ang<a.ang;    }};typedef Vector Point;int n,vx,vy,x[N],y[N];long long ans;Point q[N];long long Abs(long long x){return (x>0)?x:-x;}int main(){    scanf("%d",&n);    for (int i=1;i<=n;++i) scanf("%d%d",&x[i],&y[i]);    for (int i=1;i<=n;++i)    {        int cnt=0;        for (int j=1;j<=n;++j)            if (i!=j) q[++cnt]=Point(x[j]-x[i],y[j]-y[i]);        sort(q+1,q+cnt+1);        for (int i=1;i<=cnt;++i) q[cnt+i]=q[i],q[cnt+i].ang+=2*pi;        int l=1,r=0;        while (l<=cnt)        {            if (l>r) r=l,vx=0,vy=0;            while (r<=cnt<<1&&q[r].ang<q[l].ang+pi)            {                ans+=Abs((long long)q[r].x*vy-(long long)q[r].y*vx);                if (r<=cnt) vx+=q[r].x,vy+=q[r].y;                ++r;            }            vx-=q[l].x,vy-=q[l].y;            ++l;        }    }    ans=ans*5/3;    printf("%lld.%lld\n",ans/10,ans%10);}
0 0