zoukankan      html  css  js  c++  java
  • 「LOJ 2882」「JOISC 2014 Day4」两个人的星座「极角排序」

    https://loj.ac/problem/2882

    题解

    对于两个相离的三角形,一定有两条内公切线(即两个三角形在这条线两侧,并且线上分别有两个三角形的一个顶点)

    暴力的方法是(O(n^2))枚举公切线然后计算,复杂度(O(n^3))

    优化即为先枚举一个点定为极点,然后把剩下所有点极角排序。这时候初始假设公切线是x轴统计信息,然后按极角顺序枚举另一个点,这样每次仅有一个点会改变他所在的区域,直接修改信息和统计答案。最后答案除以4。

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

    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    typedef double db;
    const int N = 3005;
    const db pi = acos(-1.0);
    struct point {
    	int x, y, c; db k;
    	point(int a = 0, int b = 0) : x(a), y(b) {}
    	point operator + (point b) { return point(x + b.x, y + b.y); }
    	point operator - (point b) { return point(x - b.x, y - b.y); }
    	db dot(point b) { return x * b.x + y * b.y; }
    	db det(point b) { return x * b.y - y * b.x; }
    	db dis(point b) { return sqrt((x - b.x) * (x - b.x) + (y - b.y) * (y - b.y)); }
    	db len() { return sqrt(x * x + y * y); }
    	db theta() { return atan2(y, x); }
    	bool operator < (const point &b) const {
    		return k < b.k;
    	}
    } a[N], b[N];
    int n, bl[N];
    ll ans, cnt[2][5];
    ll calc(int k, int x) {
    	ll res = 1;
    	for(int i = 0; i < 3; i ++)
    		if(x != i) res *= cnt[k][i];
    	return res;
    }
    void solve(int u) {
    	int m = 0;
    	for(int i = 1; i <= n; i ++) if(i != u) 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 = b[i].theta();
    		if(b[i].k <= 0) b[i].k += pi;
    	} 
    	memset(cnt, 0, sizeof cnt);
    	sort(b + 1, b + m + 1);
    	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;
    		}
    		cnt[bl[i]][b[i].c] ++;
    	}
    	for(int i = 1; i <= m; i ++) {
    		cnt[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);
    		cnt[bl[i] ^= 1][b[i].c] ++;
    	}
    }
    int main() {
    	//freopen("input", "r", stdin);
    	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
    ", ans >> 2);
    	return 0;
    }
    
  • 相关阅读:
    测试方案
    如何编写一个好的测试计划
    一个好的测试过程
    java后台生成echarts图表并保存图片
    Javascript数组排序,并获取排序后位置对应的原索引(堆排序实现)
    修改tomcat编码方式
    json序列化反序列化后function丢失
    Mysql数据库存取性能优化
    java创建文件
    Java POI导出ppt简单实现
  • 原文地址:https://www.cnblogs.com/hongzy/p/12204814.html
Copyright © 2011-2022 走看看