CF1284E(几何)
题意:有n个点,对于每个点p有k个四边形包含p,求k的和(4个点相同的四边形只算一次,三点不共线
首先由于三点不共线,所以对于一个合法答案p一定在四边形的两个三角形内
所以答案就变成算有多少个三角形包含一个点
首先枚举被包含的这个点p,然后以p为原点建坐标系,一个三角形不包含原点就是有一条经过原点的直线可以把这个三角形画到一个半平面以内
把剩下的点先分成上下两份,极角排序以后把这条线绕原点转动
由于三点不共线所以每次转动就是看上方的下一个点和下方的下一个点那个转动角度较小,也就是比较一下这两个点的左右关系
如果下方的点在上方的右边就转上面,否则转下面然后减掉和这个点在同一半平面以内的三角形
最后答案乘n-4(四边形的第4个点)除以2(算了两遍)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int M = 300001;
int n,m;
LL res;
struct vv
{
int x,y;
vv (int X,int Y) : x(X), y(Y){}
vv(){}
} p[M],u[M],d[M];
vv operator -(const vv&a,const vv&b) {return vv(a.x-b.x,a.y-b.y); }
LL operator ^(const vv&a,const vv&b) {return (LL)a.x*b.y-(LL)a.y*b.x;}
bool cmp(vv a, vv b)
{
return (a^b)>=0;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);
for(int i=1;i<=n;i++)
{
int cu=0, cd=0;
for(int j=1;j<=n;j++)
{
if(p[j].y>p[i].y) u[++cu]=p[j]-p[i];
if(p[j].y<p[i].y) d[++cd]=p[j]-p[i];
if(p[j].y==p[i].y && p[j].x>p[i].x) u[++cu]=p[j]-p[i];
if(p[j].y==p[i].y && p[j].x<p[i].x) d[++cd]=p[j]-p[i];
}
sort(u+1,u+1+cu,cmp); sort(d+1,d+1+cd,cmp);
res=(res+(n-1ll)*(n-2ll)*(n-3ll)/6);
int tu=0, td=0;
while(tu+td!=cu+cd)
{
if(td==cd || (tu!=cu && (d[td+1]^u[tu+1])>0))
{
tu++;
res=(res-((LL)cu-tu+td)*(cu-tu-1ll+td)/2);
}
else
{
td++;
res=(res-((LL)cd-td+tu)*(cd-td-1ll+tu)/2);
}
}
}
res=res*(n-4ll)/2ll;
printf("%lld",res);
}