• [CF1025F]Disjoint Triangles[极角排序+组合计数]


    题意

    平面上有 (n) 个点,选出六个点构成两个三角形,问有多少种构造方式使得两个三角形没有交集。

    (nleq 2000)

    分析

    • 枚举连接两个三角形的两个顶点,同时能够将两个三角形划分在直线两侧的直线。

    • 考虑每个点和 (n-1) 个点连边,这些边按照极角排序,并维护直线左侧有多少个点(如果跨过极角等于 (pi) 就再加一倍直线,同时弧度 (+2pi)),那么答案增加量就是 (inom{{cnt}_l}{2} imesinom{n-2-{cnt}_l}{2})

    • 每对三角形会有两条直线计算到,所以最后答案除以2.

    • 时间复杂度 (O(n^2logn))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].lst,v=e[i].to)
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define pb push_back
    typedef long long LL;
    inline int gi(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch))	{if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
    	return x*f;
    }
    template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
    template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
    typedef double db;
    const db INF=1.0*1e14,pi=acos(-1.0);
    const int N=4004;
    int n;
    LL ans;
    db ang[N],x[N],y[N];
    LL C(int n){
    	return 1ll*n*(n-1)/2;
    }
    int main(){
    	n=gi();
    	rep(i,1,n) scanf("%lf%lf",&x[i],&y[i]);
    	rep(o,1,n){
    		int ndc=0;
    		rep(i,1,n) if(o^i) ang[++ndc]=atan2(y[i]-y[o],x[i]-x[o]);
    		sort(ang+1,ang+ndc+1);
    		rep(i,1,n-1) ang[++ndc]=ang[i]+2*pi;
    		for(int i=1,j=1;i<n;++i){
    			while(ang[j]-ang[i]<=pi) ++j;
    			int l=j-i-1,r=n-2-l;
    			ans+=C(l)*C(r);
    		}
    	}
    	printf("%lld
    ",ans>>1);
    	return 0;
    }
    
    
  • 相关阅读:
    boost::ptree;boost::xml_parser
    boost::array
    boost::timer
    boost::gregorian日期
    boost::algorithm/string.hpp
    boost::lexical_cast
    QT::绘图
    QT::透明
    centos上freefilesync与定时任务
    centos上安装freefilesync工具配置说明
  • 原文地址:https://www.cnblogs.com/yqgAKIOI/p/10109511.html
Copyright © 2020-2023  润新知