zoukankan      html  css  js  c++  java
  • LOJ2882 两个人的星座

    两个人的星座

    JOI 酱和 IOI 酱是一对亲密无间的好朋友。某天,JOI 酱与 IOI 酱决定去山上的某个观象台进行天体观测。

    从观象台上可以观测到 (N) 颗星星,编号为 (1dots N)。每颗星星的颜色为红色、蓝色、黄色中的一种。

    在观象台上观测到的星星可以用坐标系上的点来表示。在坐标系上,(i) 号星对应的点为 (P_i),位于 ((X_i,Y_i))。坐标系上的点两两不同,且不存在三点共线。

    JOI 酱和 IOI 酱想要设立一个叫做「JOIOI 座」的星座。首先。两个人决定使用红色、蓝色、黄色三种颜色的星各一个构成的三角形。他们将这样的三角形称作「好三角形」。

    两人将满足以下条件的一对(两个,无序)好三角形作为「JOIOI 座的候补」:

    • 两个三角形没有公共点(包括内部和边界)。换言之,两个三角形之间既不相交,也不存在某个三角形包含另一个三角形。

    JOI 酱和 IOI 酱想知道构成 JOIOI 座的候补一共有多少种方案。

    注意,如果构成三角形的 (6) 个点一样,但是构成三角形的方式不同,算作不同的方案。

    现在给出观象台上能观测到的星星的信息,请求出构成「JOIOI 座的候补」一共有多少种方案。

    对于所有数据,(6le Nle 3000,) (-10^5le X_i, Y_ile 10^5,) (C_i=0)(1)(2),保证任何一种颜色的星星都有至少一颗,星星坐标互不相同,无三星共线。

    题解

    http://jklover.hs-blog.cf/2020/04/13/Loj-2882-两个人的星座/#more

    两个三角形如果相离,则一定可以用公切线分开。

    枚举两个点的连线作为公切线,统计两个半平面中各类颜色点的数目,时间复杂度(O(n^3))

    优化一下,先枚举一个点作为原点,对其他点极角排序。

    再枚举另一个点,用前缀和询问两个半平面中各类颜色点的数目。

    由于两个相离的三角形通过顶点相连可以产生4根公切线,其中有2根对使得这对三角形被统计到,所以最后还需要将答案除以2。

    时间复杂度(O(n^2log n))

    IN int sign(int64 x){
    	return x>=0;
    }
    
    struct point {int64 x,y;int c;};
    
    IN point operator-(CO point&a,CO point&b){
    	return {a.x-b.x,a.y-b.y,a.c};
    }
    IN int64 cross(CO point&a,CO point&b){
    	return a.x*b.y-a.y*b.x;
    }
    IN bool operator<(CO point&a,CO point&b){
    	return sign(a.y)!=sign(b.y)?sign(a.y)>sign(b.y):cross(a,b)>0;
    }
    
    CO int N=3e3+10;
    int n;
    point p[N],q[N];
    int sum[N][3],tmp[2][3];
    
    int query(int l,int r,int c){
    	if(l>r) return 0;
    	return sum[r][c]-sum[l-1][c];
    }
    int64 solve(){
    	for(int i=2;i<=n;++i) q[i-1]=p[i]-p[1];
    	sort(q+1,q+n);
    	for(int i=1;i<n;++i)
    		copy(sum[i-1],sum[i-1]+3,sum[i]),++sum[i][q[i].c];
    	int64 ans=0;
    	for(int i=1;i<n;++i){
    		point iq=(point){0,0}-q[i];
    		int l=i,r=lower_bound(q+1,q+n,iq)-q;
    		for(int j=0;j<3;++j){
    			tmp[0][j]=query(1,l-1,j)+query(r,n-1,j);
    			tmp[1][j]=query(l+1,r-1,j);
    		}
    		int c=p[1].c,d=q[i].c;
    		for(int cur=0;cur<2;++cur){
    			int64 prod=1;
    			for(int j=0;j<3;++j){
    				if(c!=j) prod*=tmp[cur][j];
    				if(d!=j) prod*=tmp[cur^1][j];
    			}
    			ans+=prod;
    		}
    	}
    	return ans;
    }
    int main(){
    	read(n);
    	for(int i=1;i<=n;++i) read(p[i].x),read(p[i].y),read(p[i].c);
    	int64 ans=0;
    	for(int i=1;i<=n;++i){
    		swap(p[1],p[i]);
    		ans+=solve();
    		swap(p[1],p[i]);
    	}
    	printf("%lld
    ",ans/=2);
    	return 0;
    }
    
  • 相关阅读:
    shell特殊符号cut命令 sort_wc_uniq命令 tee_tr_split命令 shell特殊符号
    管道符和作业控制 shell变量 环境变量配置文件
    8.1 shell介绍 8.2 命令历史 8.3 命令补全和别名 8.4 通配符 8.5 输入输出重定向 
    yum更换国内源 yum下载rpm包 源码包安装
    mysql Communication link failure, message from server: "Can't get hostname for your address"
    7.1 安装软件包的三种方法 7.2 rpm包介绍 7.3 rpm工具用法 7.4 yum工具用法 7.5 yum搭建本地仓库
    java 对象数组
    zip压缩工具 tar打包 打包并压缩
    java链接mysql 中文乱码
    压缩打包介绍/gzip压缩工具/bzip2压缩工具/xz压缩工具
  • 原文地址:https://www.cnblogs.com/autoint/p/12789855.html
Copyright © 2011-2022 走看看