Angle Beats Gym - 102361A(计算几何)

Angle Beats

\[
Time Limit: 4000 ms \quad Memory Limit: 1048576 kB
\]

题意

给出 \(n\) 个初始点以及 \(q\) 次询问,每次询问给出一个询问点 \(Q\),求包括 \(Q\) 点的直角三角形有多少个。保证 \(n+q\) 个点都不重复。

思路

  1. 对于每次询问,当 \(Q\) 为直角点时,以 \(Q\) 为原点,对 \(n\) 个点做象限极角排序,然后用双指针 \(L\)、 \(R\) 维护直角三角形的个数。 \(L\) 指针用来枚举其中的一条直角边, \(R\) 指针用来寻找在另一条直角边上的点有多少个,每次找 \(QL\) 这条边逆时针方向的另一条边\(QR\)。所以当 \(L\) 往逆时针转动时,\(R\) 也会往逆时针转动,那么就可以用双指针直接维护出来了,特别注意一下多个点在同一条直线上的情况就可以了。
  2. 若 \(Q\) 不是直角点时,可以离线处理,把 \(n+q\) 个点全部存出来,然后枚举以 \(n\) 个初始点为直角点时,对哪些的 \(Q\) 点有贡献,维护方法同上。

最后的复杂度为 \(O\left(qnC_1 + n(n+q)C_2\right)\),\(C_1、C_2\) 取决于在枚举直角点为原点后,到原点在同一条直线上的点数量。
我试过把 \(n+q\) 个节点全部提取出来,然后暴力枚举每个点为直角点的情况,但是这样复杂度会 \(T\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e4+10;

struct Point {
    ll x, y;
    int id;
} p[maxn], be[maxn];
int n, m;
int ans[maxn];

int cmp1(Point a, Point b) {
    ll d = a.x*b.y - b.x*a.y;
    if(d == 0) {
        return a.x<b.x;
    } else {
        return d>0;
    }
}
int Qua(Point a) {
    if(a.x>0 && a.y>=0) return 1;
    if(a.x<=0 && a.y>0) return 2;
    if(a.x<0 && a.y<=0) return 3;
    if(a.x>=0 && a.y<0) return 4;
}

int cmp(Point a, Point b) {
    if(Qua(a) == Qua(b))    return cmp1(a, b);
    else    return Qua(a)<Qua(b);
}

ll check(Point a, Point b) {
    return a.x*b.x + a.y*b.y;
}

ll chaji(Point a, Point b) {
    return a.x*b.y - b.x*a.y;
}

ll work(Point pp) {
    for(int i=1; i<=n; i++) {
        p[i] = be[i];
        p[i].x -= pp.x;
        p[i].y -= pp.y;
    }
    p[0] = pp;
    sort(p+1, p+1+n, cmp);
    for(int j=1; j<=n; j++) {
        p[j+n] = p[j];
    }
    ll ans = 0;
    int R = 2;
    for(int L=1; L<=n; L++) {
        while(R<=2*n) {
            if(chaji(p[L], p[R]) < 0)   break;
            if(check(p[L], p[R]) <= 0)  break;
            R++;
        }
        int tR = R;
        while(tR<=2*n) {
            if(chaji(p[L], p[tR]) <= 0) break;
            if(check(p[L], p[tR]) != 0) break;
            ans++;
            tR++;
        }
    }
    return ans;
}

int main(){
    // freopen("in", "r", stdin);
    while(~scanf("%d%d", &n, &m)) {
        int all = 0;
        for(int i=1; i<=n; i++) {
            all++;
            int x, y;
            scanf("%d%d", &x, &y);
            p[all].x = x, p[all].y = y, p[all].id = 0;
            be[all] = p[all];
        }
        for(int i=1; i<=m; i++) {
            all++;
            int x, y;
            scanf("%d%d", &x, &y);
            p[all].x = x, p[all].y = y, p[all].id = i;
            be[all] = p[all];
            ans[i] = work(p[all]);
        }
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=all; j++) {
                p[j] = be[j];
            }
            p[0] = be[i];
            int flag = 0;
            for(int j=1; j<=all; j++) {
                if(p[j].x == p[0].x && p[j].y == p[0].y)    flag = 1;
                if(flag)    p[j] = p[j+1];
                p[j].x -= p[0].x;
                p[j].y -= p[0].y;
            }

            int nn = all-1;
            sort(p+1, p+1+nn, cmp);
            for(int j=1; j<=nn; j++) {
                p[j+nn] = p[j];
            }
            int R = 2;
            for(int L=1; L<=nn; L++) {
                int id = 0;
                if(p[0].id) id = p[0].id;
                if(p[L].id) id = p[L].id;
                while(R<=2*nn) {
                    if(chaji(p[L], p[R]) < 0)   break;
                    if(check(p[L], p[R]) <= 0)  break;
                    R++;
                }
                int tR = R;
                while(tR<=2*nn) {
                    if(chaji(p[L], p[tR]) <= 0) break;
                    if(check(p[L], p[tR]) != 0) break;
                    if(id == 0) {
                        if(p[tR].id)    ans[p[tR].id]++;
                    } else {
                        if(p[tR].id == 0)   ans[id]++;
                    }
                    tR++;
                }
            }
        }
        for(int i=1; i<=m; i++) {
            printf("%d\n", ans[i]);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/11631203.html

时间: 2024-10-11 07:39:28

Angle Beats Gym - 102361A(计算几何)的相关文章

Gym102361A Angle Beats(直角三角形 计算几何)题解

题意: \(n\)个点,\(q\)个询问,每次问包含询问点的直角三角形有几个 思路: 代码: #include<bits/stdc++.h> using namespace std; const int maxn = 8000 + 10; typedef long long ll; const ll mod = 998244353; typedef unsigned long long ull; struct Point{ ll x, y; int flag; }be[maxn], p[max

Codeforces Gym 102361A Angle Beats CCPC2019秦皇岛A题 题解

题目链接:https://codeforces.com/gym/102361/problem/A 题意:给定二维平面上的\(n\)个点,\(q\)次询问,每次加入一个点,询问平面上有几个包含该点的直角三角形. 分析:这是一篇鸽了很久的题解,主要原因就是现场赛的时候这题惨遭卡常,锅++.现在回过头来想这题,主要问题出在现场赛时误判了\(map\)的时间复杂度,把极角排序的正确想法成功叉掉,以及现场赛时候的共线计数使用了\(gcd\),使得整体复杂度上升.(但还是有大佬拿gcd思想过了,我太菜了)现

Gym 101055A 计算几何,暴力

http://codeforces.com/gym/101055/problem/A 题目:给定一些三维空间的点,要你找一个平面,能覆盖尽量多的点,只要求输出点数即可.n<=50 因为数据量小,我们考虑暴力. 首先,三个不在同一条直线的点,确定一个平面,然后枚举其他的点.判断一下,这样的复杂度是n^4.可以接受 特判.所有点都在同一条直线.直接输出n. 后面的,枚举三个点后,能算出这个平面的法向量,然后枚举其他点,与法向量的数量积是0的,就可以ans++ #include <cstdio>

Rasheda And The Zeriba Gym - 100283A ? 计算几何

http://codeforces.com/gym/100283/problem/A 考虑到多边形是不稳定的,是可以变来变去的. 那么总是可以把每个点放到圆上. 所以只需要判断圆心角是不是小于等于360即可. #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h>

Gym - 101845D 计算几何

Ignacio is a famous mathematician, some time ago he was married with Dolly, a famous scientific, at that time they bought a huge piece of land that they would use to construct a national university, they chose the land with the following property: if

Gym 101464C - 计算几何+二分(uva1463)

网络赛的A题.不是很难,但是我觉得对代码能力的要求还是挺高的. 注意模块化. 因为是浮点数,所以二分用的很多很多. 参考 https://blog.csdn.net/njupt_lyy/article/details/81256538?utm_source=blogxgwz4 对半径二分,这样我们只需要判断能不能放的下这个圆.这时,通过给定的半径,对于每一条线段可以找到一个区间(或者为空),使得圆心不能落在这个区间上,我们只需要判断区间的并集是否覆盖了[0,L].那么如何去找到这个区间呢?对于每

【2019CCPC秦皇岛:A】Angle Beats 分类讨论 (unordered_map 加 hash)

题意:n个给定点,q个询问点,每次询问给出一个坐标A,问从n中选定两个点B,C,有多少种方案使得ABC是个直角三角形. 思路:直角三角形能想的就那几个,枚举边,枚举顶点,这个题都行,写的枚举顶点的,A点分两种情况,1是直角,2是非直角.防止误差,用分数表示斜率,然后用了map<pair<int,int> int> 发现t了,改成unordered_map发现这个unordered_map只能映射一个,即unordered_map<ll, int>,所以得用到hash,把

codeforces gym 102268 300iq round

暂时只能写签到题,别的题解之后补 A.Angle Beats B.Best Subsequence 有点有趣的二分 显然二分之后就是找到一个长度恰好为k的合法环了 先证明一个引理,如果可以找到一个长度大于k的环一定可以找到一个长度等于k的环 固定头尾不动之后就可以使用归纳法证明一个长度大于3的环都可以删掉一个点 为啥呢?,因为考虑任意三个连续的点,除非中间的点是最小值,否则都可以删掉这个点 很容易证明长度大于3的序列至少存在一组三个连续的点满足中间的点可以删去吧 而长度恰好是3的时候吧中间的点删

2019 China Collegiate Programming Contest Qinhuangdao Onsite

目录 Contest Info Solutions A. Angle Beats D. Decimal F. Forest Program I. Invoker J. MUV LUV EXTRA Contest Info Practice Link Solved A B C D E F G H I J K L 5/12 O - - O - O - - - O ? - O 在比赛中通过 ? 赛后通过 ! 尝试了但是失败了 - 没有尝试 Solutions A. Angle Beats 题意: 给出