首页 > 其他分享 >洛谷 [AGC021B] Holes 蓝 题解

洛谷 [AGC021B] Holes 蓝 题解

时间:2022-11-09 19:57:18浏览次数:43  
标签:10 洛谷 int 题解 top Holes stk poi PDD

前言

学校基础模拟赛的题,当时有思路但是不太会写凸包就没做,下来看了看,自己的思路大部分是正确的,有些细节没有想到,在此写篇题解。

我用的是 Andrew 求凸包。

思路

答案为 0 的点

题目说:坐标系半径 \(R=10^{10^{10^{10}}}\),你可以感受一下这个数字的大小,这个数字比 \(10^6\) 要大得多得多!根本不在一个数量级上!如果我们把题目中的所有点的凸包求出来,那么随机出来的点在这个凸包里面的概率非常非常小,小到在精确度 \(10^{-5}\) 的要求上可以忽略

这样就可以得到很重要的一个结论:对于不在凸包上的所有点,它们的答案为 0

凸包上的点

考虑凸包上的点的答案怎么求。到点的距离这个东西,初中数学书上有一条重要的定理:一个线段的中垂线到这个线段的两个端点的距离相等。那对于一个点,如何求凸包上的那个点离它最近呢?不太好求,换一种思路,能不能求出:对于凸包上的每个点 \(A_i\),求出与之对应的极大的一个区域,使得这个区域上的所有点离点 \(A_i\) 的距离是最近的,且不在这个区域上的所有点离点 \(A_i\) 的距离不是最近的。先上图:

两条粉色的线分别为线段 \(AB,BC\) 的中垂线,那么能够直观感受到蓝色框框就是所求的极大的区域,这个区域里的所有点离点 \(B\) 是最近的。至于为什么不加凸包里面的部分,其实加和不加都一样,这么一点点面积,怎么能够和我 \(R=10^{10^{10^{10}}}\) 的坐标系相比较呢?根本不会影响答案。

那么点 \(B\) 的答案是多少呢?比较显然,就是两个中垂线所成夹角再除以 \(360^\circ\),中垂线夹角也就是图中灰色的角。

怎么方便地求角度

你直接硬算肯定没问题,但是又更简单的方法,还拿上图举例子,如果我们能求出 \(\angle ABC\) 的大小,那么所求的灰色角的角度就是 \(180^\circ - \angle ABC\),那么考虑如何求 \(\angle ABC\)

高中数学书上有一条重要的定理“余弦定理”:在 \(\triangle ABC\),\(\cos C = \dfrac{a^2+b^2-c^2}{2ab}\),其中线段 \(a,b,c\) 分别为角 \(A,B,C\) 对着的边,即:\(a=BC,b=AC,c=AB\)。

那么要求出 \(\angle ABC\),我们可以先求出 \(\cos \angle ABC\),再用反三角函数即可求出 \(\angle ABC\)

在这个图中 \(\cos \angle ABC = \dfrac{AB^2+BC^2-AC^2}{2 \cdot AB \cdot BC}\),而点 \(A,B,C\) 的坐标都是已知的,那么很容易就能求出来,不赘述了。

细节问题

首先考虑如果一些点共线了该怎么办?如下图:

你还是每两个相邻点作中垂线,然后划分区域,得到下图:

不用我多说,聪明的你一定能够知道每个区域是对应哪个点的,那么你考虑 \(C,D,E,F,G\) 这个五个点的答案分别是多少,答案:除了最左边的点 \(C\) 和最右边的点 \(G\) 的答案为 \(0.5\),其他点的答案均为 \(0\)

为什么?虽然说 \(D,E,F\) 这三个点的区域也是无限向外延申的,但是他们可以形象地理解为“一维延伸”,确实,与直线垂直的方向上是无限延伸的,但是直线方向的长度是固定的;而对于 \(C,D\) 两点,他们可以形象地理解为“二维延伸”,与直线垂直的方向上是无限延伸的,直线方向上也是无限延伸的。还是那句话:“一维延伸”的区域怎么能够和我 \(R=10^{10^{10^{10}}}\) 的坐标系相比较呢?根本不会影响答案!

这说明求凸包时,要把共线的点当作不在凸包上,否则答案会错。

还有就是,如果只有一个点,那么直接输出 1 即可,这个很好理解。

Code

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define x first
#define y second

using namespace std;

typedef pair<double, double> PDD;
const int N = 210;
const double pi = acos(-1), pi_2 = 2 * acos(-1);

int n;
int top, stk[N];
struct warma
{
    PDD q;
    int id;
} poi[N];
double ans[N];

bool cmp(warma a, warma b)
{
    return a.q < b.q;
}

double get_dist(PDD a, PDD b)
{
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}

double cross(PDD a, PDD b)
{
    return a.x * b.y - a.y * b.x;
}

double area(PDD a, PDD b, PDD c)
{
    PDD ab = (PDD){b.x - a.x, b.y - a.y};
    PDD ac = (PDD){c.x - a.x, c.y - a.y};
    return cross(ab, ac);
}

void andrew()
{
    sort(poi + 1, poi + 1 + n, cmp);
    top = 0;
    for (int i = 1; i <= n; i ++ )
    {
        while (top >= 2 && area(poi[stk[top - 1]].q, poi[stk[top]].q, poi[i].q) < 0) top -- ;
        stk[ ++ top] = i;
    }
    for (int i = n - 1; i >= 1; i -- )
    {
        while (top >= 2 && area(poi[stk[top - 1]].q, poi[stk[top]].q, poi[i].q) < 0) top -- ;
        stk[ ++ top] = i;
    }
    top -- ;
    stk[0] = stk[top], stk[top + 1] = stk[1]; //这么做为了防止越界,把它变成一个“环”
    return;
}


int main()
{
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    cin >> n;
    if (n == 1)
    {
        printf("1\n");
        return 0;
    }
    for (int i = 1; i <= n; i ++ ) cin >> poi[i].q.x >> poi[i].q.y, poi[i].id = i;
    andrew();
    //以上是求凸包
    for (int i = 1; i <= top; i ++ )
    {
        double a = get_dist(poi[stk[i - 1]].q, poi[stk[i]].q);
        double b = get_dist(poi[stk[i]].q, poi[stk[i + 1]].q);
        double c = get_dist(poi[stk[i - 1]].q, poi[stk[i + 1]].q);
        double angle = pi - acos((a * a + b * b - c * c) / (2 * a * b)); //余弦定理
        ans[poi[stk[i]].id] = angle / pi_2;
    }
    for (int i = 1; i <= n; i ++ ) printf("%.10lf\n", ans[i]);
    return 0;
}

尾声

细节真是太多了,写这篇题解花了大概俩小时吧,还是有一些收获!还有 16 天左右就要 NOIP 了,准备退役啦!完结撒花!

标签:10,洛谷,int,题解,top,Holes,stk,poi,PDD
From: https://www.cnblogs.com/LittleMoMol-kawayi/p/solution_LuoGu_AT_agc021_b.html

相关文章

  • 2022CSP-J题解
    2022CSP-J如期举行,<del>本人在封控区参加不了</del>,CCF收钱之后题目确实是变简单了,所以半场外人士写了一片题解,希望对各位大佬有帮助。#T1-乘方第一题往往没有**实现难......
  • 二分查找与二分答案题解
    此类题目的特征为数据量大,数据为升序或降序根本目的是通过二分法快速缩小答案范围,然后对比数据或验证答案2.1二分查找输出时注意mid是否为第一个出现的答案1#incl......
  • CF1285D Dr. Evil Underscores 题解
    给定一个序列\(a\),选取一个\(x\),使\(\max_{i=1}^na_i\oplusx\)最小。看到这种题直接按位考虑,如果最高位全是\(1\)那把\(x\)的这位全变成\(1\),如果最高位全是\(......
  • 洛谷P1434滑雪分析
    [SHOI2002]滑雪题目描述Michael喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来......
  • 洛谷P1605题解分析
    迷宫题目描述给定一个\(N\timesM\)方格的迷宫,迷宫里有\(T\)处障碍,障碍处不可通过。在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障......
  • CF1747 题解
    比赛链接:https://codeforces.com/contest/1747题解:AB水题//bySkyRainWind#include<cstdio>#include<vector>#include<cstring>#include<iostream>#include......
  • P1688 新单词接龙问题 题解
    大家好,我喜欢Hash,所以我用Hash通过了这道题。思路:处理方法有点类似于P6521首先我们最终接出的字符串要求其中的小字符串按字典序排序,那么我们就将所有字符串排好序......
  • 问题解决-白鹭引擎Egret Wing3修改项目内容后进行调试,项目仍显示修改前样式
    问题描述:修改前: 修改后: 解决方法:点击上方菜单栏项目-清理,进行项目清理    点击菜单栏项目-调试  重新进行调试。  调试成功后,问题成功解......
  • 问题解决-白鹭引擎Egret Wing3调试出错,输出台显示乱码而且编译终止问题Failed to load
    问题描述:Failedtoloadresource:theserverrespondedwithastatusof404()未能加载资源:服务器响应,状态为404() 解决方法:卸载引擎并重新安装,安装时使用默认路径(C......
  • maven打包失败,Could not resolve dependencies for project...Could not find artifac
    一、问题原因:在阿里私服或者Maven的中央仓库找不到Pom文件引入的Jar,也就是说,你想引的依赖Jar包根本没有成功加载到项目中。二、分析2.1这个包可能处于隐患或者其他原因,原作......