HDU 5784 How Many Triangles
计算几何,极角排序,双指针,二分。
直接找锐角三角形的个数不好找,可以通过反面来求解。
首先,$n$个点最多能组成三角形个数有$C_n^3$个,但是这之中还包括了直角三角形,钝角三角形,平角三角形,我们需要减去这些三角形的个数。
如果在$n$个点中找到了$A$个直角,那么必然有$A$个直角三角形。
同理,如果找到了$B$个钝角,那么必然有$B$个钝角三角形。
同理,如果找到了$C$个平角,那么必然有$C$个平角三角形。
那么答案:$ans=C_n^3-A-B-C$。
接下里的任务就是求解$A$,$B$,$C$的总和是多少。
计算$A+B+C$,可以枚举一个点$P$作为三角形顶点,然后剩余的点根据$P$点作为原点进行极角排序,然后进行尺取(或者二分)。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0),eps=1e-8; void File() { freopen("D:\\in.txt","r",stdin); freopen("D:\\out.txt","w",stdout); } template <class T> inline void read(T &x) { char c = getchar(); x = 0;while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } } const int MAX = 2010; struct point{ LL x, y; }s[MAX],t[MAX]; int n; LL CrossProd(point p0, point p1, point p2){ return (p1.x-p0.x)*(p2.y-p0.y) - (p1.y-p0.y)*(p2.x-p0.x); } bool cmp(const point &a, const point &b) { if (a.y == 0 && b.y == 0 && a.x*b.x <= 0) return a.x>b.x; if (a.y == 0 && a.x >= 0 && b.y != 0) return true; if (b.y == 0 && b.x >= 0 && a.y != 0) return false; if (b.y*a.y <= 0) return a.y>b.y; point one; one.y = one.x = 0; return CrossProd(one,a,b) > 0 || (CrossProd(one,a,b) == 0 && a.x < b.x); } LL dis2(point a,point b) { return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y); } bool check(point a,point b,point c) { LL lena=dis2(b,c); LL lenb=dis2(a,c); LL lenc=dis2(a,b); if(lenb+lenc-lena<=0) return 1; return 0; } int main() { while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) scanf("%lld%lld",&t[i].x,&t[i].y); LL ans=(LL)n*(LL)(n-1)*(LL)(n-2)/(LL)6; int sz; for(int i=1;i<=n;i++) { sz=0; for(int j=1;j<=n;j++) { if(i==j) continue; s[sz].x=t[j].x-t[i].x; s[sz].y=t[j].y-t[i].y; sz++; } sort(s,s+sz,cmp); for(int j=0;j<sz;j++) { point tmp; tmp.x=0; tmp.y=0; int L=j,R=sz-1,pos=-1; while(L<=R) { int mid=(L+R)/2; if(CrossProd(tmp,s[j],s[mid])>=0) L=mid+1,pos=mid; else R=mid-1; } if(pos!=-1&&pos>=j+1) { L=j+1,R=pos; int h=-1; while(L<=R) { int mid=(L+R)/2; if(check(tmp,s[j],s[mid])) R=mid-1, h=mid; else L=mid+1; } if(h!=-1) ans=ans-(LL)(pos-h+1); } if(pos!=-1&&pos+1<=sz-1) { L=pos+1,R=sz-1; int h=-1; while(L<=R) { int mid=(L+R)/2; if(check(tmp,s[j],s[mid])) L=mid+1, h=mid; else R=mid-1; } if(h!=-1) ans=ans-(LL)(h-pos); } } } printf("%lld\n",ans); } return 0; }