【BZOJ】1132: [POI2008]Tro

题意

\(n(1 \le n \le 3000)\)个点,求所有三角形的面积和。

分析

首先枚举一个点,发现把其它点按照关于这个点的极角排序后第\(i\)个点关于前面\(1\)\(i-1\)的点组成的三角形的面积之和可以用前缀和和单调性来求出(因为有正负面积之分,而正负具有单调性)。

题解

所以我们维护枚举第一个点然后将其它点按照关于这个点为原点的极角排序。然后从左往右扫,计算第\(i\)个点和前\(i-1\)个点的正向面积之和和负向面积之和(叉积来求)。
极角排序的\(O(n^2logn)\)常数超大(doge).

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int getint() {
    int x=0, c=getchar();
    for(; c<48||c>57; c=getchar());
    for(; c>47&&c<58; x=x*10+c-48, c=getchar());
    return x;
}
const int N=3005;
struct ip {
    int x, y;
    double ang;
    void init(int _x, int _y) {
        x=_x;
        y=_y;
        ang=atan2(y, x);
    }
    void read() {
        x=getint();
        y=getint();
    }
}a[N], p[N];
bool cmp(const ip &a, const ip &b) {
    return a.ang<b.ang;
}
int sumx[N], sumy[N];
int main() {
    int n=getint();
    for(int i=1; i<=n; ++i) {
        p[i].read();
    }
    ll ans=0;
    for(int i=1; i<=n; ++i) {
        int tot=0;
        for(int j=1; j<=n; ++j) {
            if(p[i].x!=p[j].x || p[i].y!=p[j].y) {
                a[++tot].init(p[j].x-p[i].x, p[j].y-p[i].y);
            }
        }
        sort(a+1, a+1+tot, cmp);
        int pos=1;
        for(int j=1; j<=tot; ++j) {
            for(; pos<j && a[j].x*a[pos].y>a[j].y*a[pos].x; ++pos);
            ans+=(ll)a[j].y*(sumx[j-1]-sumx[pos-1])-(ll)a[j].x*(sumy[j-1]-sumy[pos-1]);
            ans+=(ll)a[j].x*sumy[pos-1]-(ll)a[j].y*sumx[pos-1];
            sumx[j]=sumx[j-1]+a[j].x;
            sumy[j]=sumy[j-1]+a[j].y;
        }
    }
    ans/=3;
    ans*=10;
    ans/=2;
    printf("%lld.%lld\n", ans/10, ans%10);
    return 0;
}

转载于:https://www.cnblogs.com/iwtwiioi/p/4985660.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值