cf1284-New-Year-and-Castle-Construction-计算几何

题目

题目链接

内容

二维平面中有n个点,定义函数 f ( i ) f(i) f(i),剩余n-1个中选取4个点,这4个点组成的四边形严格包含第 i i i个点,这样的方案有 f ( i ) f(i) f(i)种,求 ∑ i = 1 n f ( i ) \sum_{i=1}^nf(i) i=1nf(i)

分析

考虑一下容斥, f ( i ) = f(i)= f(i)=所有的情况-不包含第 i i i个点的情况

所有的情况= C n − 1 4 C_{n-1}^4 Cn14 (剩余的n-1个点中选4个点)

如何计算不包含第 i i i个点情况?

首先以第 i i i个点为原点进行极角排序,从小到大枚举每一个点,以当前点和原点的连线将剩余n-2个点分为左右两部分. 我们还需要选择三个点,如果这三个点都在同一侧,那么这四个点组成的四边形就不会包含原点.

为了避免重复计算,我们只计算逆时针方向的那部分,也就是在与当前点叉积大于0的所有点中选三个点.

由于我们是从大到小枚举当前点的,而所有叉积的大于0的点一段连续的区域,因此我们把原点和当前点的连线设为边界,另一边界用一个单调指针维护.

因为我们要对每个点为原点的情况都进行一次极角排序,因此复杂度为 O ( n 2 l o g n ) O(n^2logn) O(n2logn)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define debug(x) cerr<<#x<<' '<<x<<'\n'
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
const int maxn=3e3+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const double eps=1e-9;
int sign(long double a) { return a<-eps?-1:a>eps; }
int cmp(long double a,long double b) { return sign(a-b); }
struct P {
    long double x,y;
    P() {}
    P(long double _x,long double _y) : x(_x),y(_y) {}
    P operator+(P p) { return {x+p.x,y+p.y}; }
    P operator-(P p) { return {x-p.x,y-p.y}; }
    P operator*(long double d) { return {x*d,y*d}; }
    P operator/(long double d) { return {x/d,y/d}; }
    bool operator==(P o) const {
        return cmp(x,o.x)==0&&cmp(y,o.y)==0;
    }
    long double len() {return sqrt(x*x+y*y);}
    long double dot(P p) { return x*p.x+y*p.y; }
    long double det(P p) { return x*p.y-y*p.x; }
    int quad() { return sign(y)==1||(sign(y)==0&&sign(x)>=0); }
};
bool cmp_angle(P a,P b) {
    int qa=a.quad(),qb=b.quad();
    if(qa==qb) {
        return a.det(b)>0;
    }
    else return qa<qb;
}
P book[maxn],a[maxn];
ll ans;
ll trans(ll x) {
    return x*(x-1)*(x-2)/6;
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    int n;
    cin>>n;
    ans=1ll*(n-1)*(n-2)*(n-3)*(n-4)/24*n;
    rep(i,1,n) {
        cin>>book[i].x>>book[i].y;
    }
    rep(i,1,n) {
        int num=0;
        rep(j,1,n) {
            if(i==j) continue;
            a[num++]=book[j]-book[i];
        }
        sort(a,a+num,cmp_angle);
        int now=0;
        rep(j,0,num-1) {
            while(now<=j) now++;
            while(now<j+num&&sign(a[j].det(a[now%num]))>0) now++;
            ans-=trans(now-j-1);
        }
    }
    cout<<ans<<'\n';
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值