【容斥(其实并不是)】【USACO】数三角形

543. [USACO Open10]数三角形

★★☆   输入文件:tricount.in   输出文件:tricount.out   简单对比
时间限制:1 s   内存限制:128 MB

在一只大灰狼偷偷潜入Farmer Don的牛群被群牛发现后,贝西现在不得不履行着她站岗的职责。

从她的守卫塔向下瞭望简直就是一件烦透了的事情。她决定做一些开发智力的小练习,防止她睡着了。

想象牧场是一个X,Y平面的网格。她将N只奶牛标记为1…N (1 <= N <= 100,000),每只奶牛的坐标为X_i,Y_i (-100,000 <= X_i <= 100,000;-100,000 <= Y_i <= 100,000; 1 <= i <=N)。然后她脑海里想象着所有可能由奶牛构成的三角形。如果一个三角形完全包含了原点(0,0),那么她称这个三角形为“黄金三角形”。原点不会落在任何一对奶牛的连线上。另外,不会有奶牛在原点。
给出奶牛的坐标,计算出有多少个“黄金三角形”。

顺便解释一下样例,考虑五只牛,坐标分别为(-5,0), (0,2), (11,2), (-11,-6), (11,-5)。
下图是由贝西视角所绘出的图示。
…………|…………
…………………..
…………|…………
——-*—-+————
…………|…………
…………|…………
…………|…………
…………|…………
…………|……….*.
.*……….|…………
…………|…………
所有十个三角形如图下所示:

通过观察,其中有5个构成了“黄金三角形”

輸入格式:
* 第一行:一个整数: N
* 第2到第N+1行: 每行两个整数X_i,Y_i,表示每只牛的坐标

樣例輸入 (文件 tricount.in):
5
-5 0
0 2
11 2
-11 -6
11 -5

輸出格式:

  • 第一行: 一行包括一个整数,表示“黄金三角形的数量”

樣例輸出 (文件 tricount.out):

5

题解:

懒得写了。。cstdio大神写得非常好。
详见——>这里写链接内容
简单说就是对极角排序,然后扫一遍,判断不符合的三角形,然后算一下就好了。

Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define LL long long
struct A{
    LL x,y;
    double z;
}a[200100];
int in(){
    int x=0; char ch=getchar(); bool f=true;
    while (ch<'0' || ch>'9'){
        if (ch=='-') f=false;
        ch=getchar();
    }
    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    if (!f) x=-x;
    return x;
}
bool cmp(A x,A y){
    return x.z<y.z;
}
LL chaji(A x,A y){
    return x.x*y.y-y.x*x.y;
}
int main(){
    int n=in();
    for (int i=1; i<=n; i++){
        a[i].x=(LL)in(),a[i].y=(LL)in();
        a[i].z=atan2((double)a[i].y,(double)a[i].x);
    }
    sort(a+1,a+n+1,cmp);
    for (int i=1; i<=n; i++) a[i+n]=(A)a[i];
    LL ans=(LL)n*(n-1)*(n-2)/6;
    int i,j;
    for (i=1,j=1; i<=n; i++){
        for (; j<i+n && chaji(a[i],a[j])>=0; j++);
        LL k=(LL)j-i-1;
        ans-=k*(k-1)/2;
    }
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值