CF1284E New Year and Castle Construction

CF1284E New Year and Castle Construction

传送门

CodeForces

题解

妙啊.

首先考虑从集合中选出\(5\)个点出来,把它称为\(\text{5-set}\)

  • \(\text{5-set}\)的凸包是一个五边形,数量为\(x_5\).
  • \(\text{5-set}\)的凸包是一个四边形,数量为\(x_4\).
  • \(\text{5-set}\)的凸包是一个三角形,数量为\(x_3\).

那么答案就是\(x_4+2x_3\),考虑每一种的贡献即可.

这时考虑怎么求这个东西?设\(X=x_5+x_4+x_3=\binom{n}{5}\),\(Y=5\times x_5+4\times x_4+3\times 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\n",5*X-Y);
    return 0;
}
posted @ 2020-05-12 12:43  fexuile  阅读(181)  评论(1编辑  收藏  举报