Po姐说
考虑两个三角形,如果这两个三角形相离,那么一定可以做出两条内公切线,否则做不出来
枚举一个点,以这个点为中心按极角序枚举另一个点,连接这两个点作出一条公切线,那么这两个三角形分别分布在这条线的两端,统计出两侧每种颜色的点之后乘法原理即可
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
typedef pair<double,int> abcd;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=3005;
struct Point{
int x,y; double tan;
Point(int x=0,int y=0):x(x),y(y) { }
void read(){
::read(x); ::read(y);
}
friend Point operator - (const Point &A,const Point &B){
return Point(A.x-B.x,A.y-B.y);
}
double Tan(){
double ret=atan2(y,x);
return ret<=0?ret+=PI:ret;
}
bool operator < (const Point &B) const{
return tan<B.tan;
}
};
int n,pnt; ll ans;
Point now;
abcd K[N];
int vst[N],cnt[5][5];
pair<Point,int> points[N],P[N],tmp[N];
inline ll calc(int x,int c){
if (x==0)
return (ll)cnt[c][1]*cnt[c][2];
else if (x==1)
return (ll)cnt[c][0]*cnt[c][2];
else
return (ll)cnt[c][0]*cnt[c][1];
}
inline void Solve(int ii)
{
cl(cnt);
pnt=0; now=points[ii].first;
for (int i=1;i<=n;i++) if (i!=ii) P[++pnt]=points[i];
for (int i=1;i<=pnt;i++) P[i].first.tan=(P[i].first-now).Tan();
sort(P+1,P+pnt+1);
for (int i=1;i<=pnt;i++)
if (P[i].first.y<now.y || (P[i].first.y==now.y && P[i].first.x>now.x))
cnt[vst[i]=0][P[i].second]++;
else
cnt[vst[i]=1][P[i].second]++;
for (int i=1;i<=pnt;i++)
{
cnt[vst[i]][P[i].second]--;
ans+=calc(points[ii].second,0)*calc(P[i].second,1);
ans+=calc(points[ii].second,1)*calc(P[i].second,0);
cnt[vst[i]^=1][P[i].second]++;
}
}
int main()
{
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n);
for (int i=1;i<=n;i++)
points[i].first.read(),read(points[i].second);
for (int i=1;i<=n;i++)
Solve(i);
printf("%lld\n",ans/4);
return 0;
}