计算几何,极角排序,双指针,二分。
直接找锐角三角形的个数不好找,可以通过反面来求解。
首先,$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-;
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 = ;while(!isdigit(c)) c = getchar();
while(isdigit(c)) { x = x * + c - ''; c = getchar(); }
} const int MAX = ;
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 == && b.y == && a.x*b.x <= ) return a.x>b.x;
if (a.y == && a.x >= && b.y != ) return true;
if (b.y == && b.x >= && a.y != ) return false;
if (b.y*a.y <= ) return a.y>b.y;
point one; one.y = one.x = ;
return CrossProd(one,a,b) > || (CrossProd(one,a,b) == && 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<=) return ;
return ;
} int main()
{
while(~scanf("%d",&n))
{
for(int i=;i<=n;i++) scanf("%lld%lld",&t[i].x,&t[i].y);
LL ans=(LL)n*(LL)(n-)*(LL)(n-)/(LL); int sz;
for(int i=;i<=n;i++)
{
sz=;
for(int j=;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=;j<sz;j++)
{
point tmp; tmp.x=; tmp.y=;
int L=j,R=sz-,pos=-;
while(L<=R)
{
int mid=(L+R)/;
if(CrossProd(tmp,s[j],s[mid])>=) L=mid+,pos=mid;
else R=mid-;
} if(pos!=-&&pos>=j+)
{
L=j+,R=pos; int h=-;
while(L<=R)
{
int mid=(L+R)/;
if(check(tmp,s[j],s[mid])) R=mid-, h=mid;
else L=mid+;
} if(h!=-) ans=ans-(LL)(pos-h+);
} if(pos!=-&&pos+<=sz-)
{
L=pos+,R=sz-; int h=-;
while(L<=R)
{
int mid=(L+R)/;
if(check(tmp,s[j],s[mid])) L=mid+, h=mid;
else R=mid-;
} if(h!=-) ans=ans-(LL)(h-pos);
}
}
}
printf("%lld\n",ans);
}
return ;
}