[BZOJ1914][Usaco2010 OPen]Triangle Counting 数三角形

来源:互联网 发布:网络危机管理 编辑:程序博客网 时间:2024/06/06 03:41

[Usaco2010 OPen]Triangle Counting 数三角形

Description
在一只大灰狼偷偷潜入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)。下图是由贝西视角所绘出的图示。
Input
第一行:一个整数: N 第2到第N+1行: 每行两个整数X_i,Y_i,表示每只牛的坐标
Output
* 第一行: 一行包括一个整数,表示“黄金三角形的数量”
Sample Input
5
-5 0
0 2
11 2
-11 -6
11 -5
Sample Output
5

Code
我们利用补集转化思想,考虑不包含原点的三角形个数.
任取一点P,原点与P的所在直线l将整个平面划分为两个半平面,而对于任意其他两点A,B,若A,B,PAB,这样每个不包含远点的三角形会算两次,因此我们可以只算一个方向的半平面.
基于此,我们对所有点按极角排序,利用twopointers扫描解决问题

Solution

#include <bits/stdc++.h>using namespace std;#define rep(i, l, r) for (int i = (l); i <= (r); i++)#define per(i, r, l) for (int i = (r); i >= (l); i--)#define MS(_) memset(_, 0, sizeof(_))#define MP make_pair#define PB push_back#define debug(...) fprintf(stderr, __VA_ARGS__)template<typename T> inline void read(T &x){    x = 0; T f = 1; char ch = getchar();    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}    while (isdigit(ch))  {x = x * 10 + ch - '0'; ch = getchar();}    x *= f;}typedef long long ll;const double eps = 1e-7;const int N = 111111;struct Vec{    double x, y, angle;    Vec() {}    Vec(double _x, double _y) : x(_x), y(_y) {angle = atan2(y, x);}    inline void cal_angle() {angle = atan2(y, x);}};inline Vec operator + (const Vec &a, const Vec &b) {return Vec(a.x+b.x, a.y+b.y);}inline Vec operator - (const Vec &a, const Vec &b) {return Vec(a.x-b.x, a.y-b.y);}template<typename T> inline Vec operator * (const Vec &a, T b) {return Vec(a.x*b, a.y*b);}template<typename T> inline Vec operator * (T a, const Vec &b) {return Vec(a*b.x, a*b.y);}inline Vec operator / (const Vec &a, double b) {return Vec(a.x/b, a.y/b);}inline double dot(const Vec &a, const Vec &b){return a.x*b.x + a.y*b.y;}inline double cross(const Vec &a, const Vec &b){return a.x*b.y - a.y*b.x;}typedef Vec Poi;inline bool angle_cmp(Poi a, Poi b) {return a.angle < b.angle;}inline bool gt0(double x) {return x-eps>0;}int n;Poi a[N];ll ans;int main(){    read(n);    rep(i, 1, n) {read(a[i].x); read(a[i].y); a[i].cal_angle();}    sort(a+1, a+1+n, angle_cmp);    int last = 1, cnt = 0;    rep(i, 1, n){        while ((last%n+1 != i) && gt0(cross(a[i], a[last%n+1]))) last++, cnt++;        ans += 1ll * cnt * (cnt-1) / 2;        cnt--;    }    printf("%lld\n", 1ll*n*(n-1)*(n-2)/6 - ans);    return 0;}
0 0
原创粉丝点击