CF1284E New Year and Castle Construction
传送门
题解
妙啊.
首先考虑从集合中选出(5)个点出来,把它称为( ext{5-set})
- ( ext{5-set})的凸包是一个五边形,数量为(x_5).
- ( ext{5-set})的凸包是一个四边形,数量为(x_4).
- ( ext{5-set})的凸包是一个三角形,数量为(x_3).
那么答案就是(x_4+2x_3),考虑每一种的贡献即可.
这时考虑怎么求这个东西?设(X=x_5+x_4+x_3=inom{n}{5}),(Y=5 imes x_5+4 imes x_4+3 imes x_3),有:(ans=5X-Y).
所以只需想怎么计算(Y),不难发现(Y)就是每一条边作为凸包中的边的总数,这个东西直接枚举边然后极角排序即可.
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2510;
struct node{int x,y;}p[N],ret[N<<2];
int n;
long long cross(node a,node b){return 1ll*a.x*b.y-1ll*a.y*b.x;}
bool cmp(node a,node b)
{
int flag1=a.y<0||(a.x>0&&!a.y);
int flag2=b.y<0||(b.x>0&&!b.y);
return flag1==flag2?cross(a,b)>0:flag1<flag2;
}
long long X,Y;
long long C5(int n){return 1ll*n*(n-1)/2*(n-2)/3*(n-3)/4*(n-4)/5;}
long long C3(int n){return 1ll*n*(n-1)/2*(n-2)/3;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d%d",&p[i].x,&p[i].y);
X=C5(n);
for(int i=1;i<=n;i++)
{
int tot=0;
for(int j=1;j<=n;j++)
if(i!=j)ret[++tot]=(node){p[j].x-p[i].x,p[j].y-p[i].y};
sort(ret+1,ret+tot+1,cmp);
for(int j=1;j<=tot;j++)ret[j+tot]=ret[j];
int pos=1;
for(int j=tot+1;j<=tot<<1;j++)
{
while(pos+tot-1<j||cross(ret[j],ret[pos])>0)pos++;
Y+=C3(j-pos);
}
}
printf("%lld
",5*X-Y);
return 0;
}