CF1284E New Year and Castle Construction

CF1284E New Year and Castle Construction

传送门

CodeForces

题解

妙啊.

首先考虑从集合中选出(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;
}
原文地址:https://www.cnblogs.com/fexuile/p/12875468.html