LOJ 2882「JOI Spring Camp 2014 Day4」两个人的星座 (极角排序)

题目链接:https://loj.ac/p/2882

极角排序:使用 \(atan2(y,x)\)函数,返回点与原点的连线与 \(x\) 轴的夹角,范围是 \([-180,180]\),可以加上 \(pi\),使得范围为 \([0,360]\)

题解:
若两个三角形不相交,则一定存在两条切线,使得两个三角形分别在切线的两端,
于是枚举每个点,按极角序枚举切线,统计切线两侧不同颜色点的数量,计算即可,具体实现参考代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 3010;
const double eps = 1e-8;
const double pi = acos(-1.0);

int n;
int c[maxn];
ll sum[3][maxn];
ll ans = 0;

struct Point{
	int x, y, c;
	double k;
	
	bool operator < (const Point &b) const {
		return k < b.k;
	}
}a[maxn], b[maxn];

Point operator + (Point a, Point b){ return (Point){a.x + b.x, a.y + b.y}; }
Point operator - (Point a, Point b){ return (Point){a.x - b.x, a.y - b.y}; }
Point operator * (Point a, int b){ return (Point){a.x * b, a.y * b}; }
Point operator / (Point a, int b){ return (Point){a.x / b, a.y / b}; }

double theta(Point a){ return atan2(a.y, a.x); }
double dis(Point a, Point b){ return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }

int bl[maxn];

ll calc(int k, int x) {
	int res = 1;
	for(int i = 0; i < 3; i ++)
		if(x != i) res *= sum[k][i];
	return res;
}

void solve(int u){
	int m = 0;
	for(int i = 1 ; i <= n ; ++i){
		if(i == u) continue;
		b[++m] = a[i];
	}
	
	for(int i = 1 ; i <= m ; ++i){
		b[i].x -= a[u].x, b[i].y -= a[u].y;
		b[i].k = theta(b[i]);
		if(b[i].k <= 0) b[i].k += pi;
	}
	
	sort(b + 1, b + 1 + m);
	memset(sum, 0, sizeof(sum));
	
	for(int i = 1 ; i <= m ; ++i) {
		if(b[i].y < 0 || (b[i].y == 0 && b[i].x > 0)) {
			bl[i] = 0;
		} else {
			bl[i] = 1;
		}
		sum[bl[i]][b[i].c]++;
	}
	
	for(int i = 1 ; i <= m ; ++i){
		sum[bl[i]][b[i].c]--;
		ans += calc(0, b[i].c) * calc(1, a[u].c);
		ans += calc(1, b[i].c) * calc(0, a[u].c);
		sum[bl[i] ^= 1][b[i].c]++;
	}
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	scanf("%d", &n);
	for(int i = 1 ; i <= n ; ++i){ scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].c); }
	
	for(int i = 1 ; i <= n ; ++i) solve(i);
	
	printf("%lld\n", ans / 4);
	return 0;
}
posted @ 2021-01-14 00:46  Tartarus_li  阅读(132)  评论(0编辑  收藏  举报