ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「JOISC 2014 Day4」两个人的星座 题解

2022-02-01 11:33:00  阅读:178  来源: 互联网

标签:ldb int 题解 Day4 long JOISC Vector 公切线 三角形


计算几何

Statement

#2882. 「JOISC 2014 Day4」两个人的星座 - 题目 - LibreOJ (loj.ac)

Solution

有性质:如果两个三角形相交或者内含,则一定不存在内公切线(即两个三角形在这条线两侧,并且线上分别有两个三角形的一个顶点)

由于题目保证了不存在三点共线,所以两个三角形相离有这样一个神仙性质:

如果两个三角形相离,那么它们有两条内公切线

所以我们得到一个暴力的算法: \(O(n^2)\)​ 枚举两点得到公切线,\(O(n)\)​ 暴力扫描一下各个点在线的上/下方并统计一下在上/下方各种颜色的点的数量,即记 \(c[1/0][y]\)​ 表示在此公切线上/下方颜色 \(y\) 的数量

容易得到此公切线的答案,这样总共是 \(O(n^3)\) 的,考虑优化

发现每次在公切线更改的时候,只有两条公切线之间的点会变化状态(eg.从线下方到上方)

所以我们考虑枚举公切线的一个端点,然后对其他点进行极角排序,这样每次只有一个点的状态改变,\(O(n^2)\)​ 即可(代码更好懂)

注意这样每对三角形同一条公切线会枚举两次,而相离的三角形有两条公切线,所以最后答案要除 \(\rm 4\)

Code

#include<bits/stdc++.h>
#define ldb long double
#define int long long
using namespace std;
const int N = 3005;
const ldb Pi = acos(-1.0);

struct Vector{
    ldb x,y; int c;
    Vector(ldb x=0,ldb y=0):x(x),y(y){}
    void scan(){scanf("%Lf %Lf %lld",&x,&y,&c);}
    void print(){printf("%.4Lf %.4Lf",x,y);}
    ldb alpha(){return atan2(y,x);}
}a[N];
struct Point{
    Vector p; ldb k;
    Point(){}
    Point(Vector p,ldb k=0):p(p),k(k){}
    bool operator<(const Point&rhs)const{
        return k<rhs.k;
    }
}p[N];
Vector operator+(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
Vector operator-(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
int c[2][5],bl[N];
int n,ans;

ldb mabs(ldb a){return a<=0?a+Pi:a;}
int calc(int op,int k){
    if(k==0)return c[op][1]*c[op][2];
    if(k==1)return c[op][0]*c[op][2];
    if(k==2)return c[op][0]*c[op][1];
}

void solve(int id){
    int cnt=0;
    for(int i=1;i<=n;++i)if(i^id)
        p[++cnt]=Point(a[i],mabs((a[i]-a[id]).alpha()));
    sort(p+1,p+1+cnt),memset(c,0,sizeof(c));
    for(int i=1;i<=cnt;++i)
        if(p[i].p.y<a[id].y||p[i].p.y==a[id].y&&p[i].p.x>a[id].x)
            c[0][p[i].p.c]++,bl[i]=0;
        else c[1][p[i].p.c]++,bl[i]=1;
    for(int i=1;i<=cnt;++i){
        c[bl[i]][p[i].p.c]--,bl[i]^=1,
        ans+=calc(0,a[id].c)*calc(1,p[i].p.c)+calc(1,a[id].c)*calc(0,p[i].p.c);
        c[bl[i]][p[i].p.c]++;
    }
}

signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;++i)a[i].scan();
    for(int i=1;i<=n;++i)solve(i);
    printf("%lld\n",ans/4);
    return 0;
}

标签:ldb,int,题解,Day4,long,JOISC,Vector,公切线,三角形
来源: https://www.cnblogs.com/wyb-sen/p/15858947.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有