Solution -「CEOI 2006」「洛谷 P5974」ANTENNA
\(\mathcal{Description}\)
Link.
给定平面上 \(n\) 个点,求最小的能覆盖其中至少 \(m\) 个点的圆半径及一个可能的圆心。
\(n\le500\),坐标值 \(X\in[0,10^4]\)。
\(\mathcal{Solution}\)
不难想到二分答案 \(r\),以每个点为圆心,\(r\) 为半径作圆,若 \(r\) 合法则能找到一个被至少 \(m\) 个圆覆盖的点。
但是圆的交极难处理,结合数据范围,考虑通过一些枚举操作来简化问题——钦定最终圆心 \(O\) 在以 \(P_i\) 为圆心的圆内,同时考虑到 \(O\) 的最优性,这一限制可以进一步加强为:圆心 \(O\) 在以 \(P_i\) 为圆心的圆周上,于是可以在圆周上按极角做扫描线。到此,我们得到 \(\mathcal O(n^2\log n\log \frac{X}{\epsilon})\) 的算法,应该能过。
接下来是计算几何算法的常见套路:基于数据随机化降低复杂度。设钦定 \(O\) 在以 \(P_i\) 为圆心的圆周上时,最小的合法半径为 \(r_i\)。假设以 \(i=1..n\) 的顺序依次计算 \(r_i\),此时我们可以用 \(\mathcal O(n\log n)\) 的时间判断某个 \(r_i\) 是否是前缀最小值。若 \(r_i\) 是前缀最小值,我们还需要 \(\mathcal O(n\log n\log\frac{X}{\epsilon})\) 的时间求出 \(r_i\) 的具体值。由于数据随机,所以期望复杂度为
T(n) &= \sum_{i=1}^n\left(\frac{\mathcal O\left(n\log n\log\frac{X}{\epsilon}\right)}{i}+\mathcal O(n\log n)\right)\\
&= \mathcal O\left(n\log^2n\log\frac{X}{\epsilon}\right).
\end{aligned}
\]
相对于期望复杂度的优化,感觉第一步通过适当枚举加强限制,简化问题的思路更为重要。不要一心想着优化复杂度就不敢考虑暴力了。
\(\mathcal{Code}\)
/*+Rainybunny+*/
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
typedef std::pair<double, bool> PDB;
#define fi first
#define se second
const int MAXN = 500;
const double EPS = 1e-7, PI = acos(-1.);
int n, m;
inline double dabs(const double u) { return u < 0. ? -u : u; }
inline int dcmp(const double u) { return dabs(u) < EPS ? 0 : u < 0 ? -1 : 1; }
inline double norm(double u) {
u = fmod(u, 2. * PI);
return u < 0. ? u + 2. * PI : u;
}
struct Point {
double x, y;
inline Point operator * (const double k) const {
return { k * x, k * y };
}
inline Point operator + (const Point& u) const {
return { x + u.x, y + u.y };
}
inline bool operator == (const Point& u) const {
return !dcmp(x - u.x) && !dcmp(y - u.y);
}
friend inline double dist(const Point& u, const Point& v) {
return sqrt((u.x - v.x) * (u.x - v.x) + (u.y - v.y) * (u.y - v.y));
}
} pnt[MAXN + 5];
inline bool check(const Point& O, const double R, Point& resO, double& resR) {
static std::vector<PDB> evt; evt.clear();
int cur = 0;
rep (i, 1, n) if (!(pnt[i] == O)) {
double d = dist(O, pnt[i]);
if (d > 2. * R) continue;
double alp = acos(0.5 * d / R);
double the = norm(atan2(pnt[i].y - O.y, pnt[i].x - O.x));
double u = norm(the - alp), v = norm(the + alp);
if (u > v) ++cur;
evt.push_back({ u, 1 }), evt.push_back({ v, 0 });
}
std::sort(evt.begin(), evt.end());
if (cur >= m - 1) {
if (R < resR) resO = O + Point{ 0, resR = R };
return true;
}
for (auto [alp, opt]: evt) {
if ((cur += opt ? 1 : -1) >= m - 1) {
if (R < resR) resO = O + Point{ cos(alp), sin(alp) } * (resR = R);
return true;
}
}
return false;
}
int main() {
scanf("%d %d", &n, &m);
rep (i, 1, n) scanf("%lf %lf", &pnt[i].x, &pnt[i].y);
std::shuffle(pnt + 1, pnt + n + 1, std::mt19937(20120712));
double ans = 7.5e3; Point ansP = { -1., -1. };
rep (i, 1, n) {
if (!check(pnt[i], ans, ansP, ans)) continue;
double l = 0., r = ans;
while (l + EPS < r) {
double mid = 0.5 * (l + r);
if (check(pnt[i], mid, ansP, ans)) r = mid;
else l = mid;
}
}
printf("%f\n%f %f\n", ans, ansP.x, ansP.y);
return 0;
}
Solution -「CEOI 2006」「洛谷 P5974」ANTENNA的更多相关文章
- 「区间DP」「洛谷P1043」数字游戏
「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...
- Solution -「JSOI 2019」「洛谷 P5334」节日庆典
\(\mathscr{Description}\) Link. 给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的). \(|S|\le3\time ...
- Solution -「洛谷 P4372」Out of Sorts P
\(\mathcal{Description}\) OurOJ & 洛谷 P4372(几乎一致) 设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...
- Solution -「POI 2010」「洛谷 P3511」MOS-Bridges
\(\mathcal{Description}\) Link.(洛谷上这翻译真的一言难尽呐. 给定一个 \(n\) 个点 \(m\) 条边的无向图,一条边 \((u,v,a,b)\) 表示从 ...
- Solution -「APIO 2016」「洛谷 P3643」划艇
\(\mathcal{Description}\) Link & 双倍经验. 给定 \(n\) 个区间 \([a_i,b_i)\)(注意原题是闭区间,这里只为方便后文描述),求 \(\ ...
- 「洛谷4197」「BZOJ3545」peak【线段树合并】
题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...
- 「洛谷3338」「ZJOI2014」力【FFT】
题目链接 [BZOJ] [洛谷] 题解 首先我们需要对这个式子进行化简,否则对着这么大一坨东西只能暴力... \[F_i=\sum_{j<i} \frac{q_iq_j}{(i-j)^2}-\s ...
- 「BZOJ2733」「洛谷3224」「HNOI2012」永无乡【线段树合并】
题目链接 [洛谷] 题解 很明显是要用线段树合并的. 对于当前的每一个连通块都建立一个权值线段树. 权值线段树处理操作中的\(k\)大的问题. 如果需要合并,那么就线段树暴力合并,时间复杂度是\(nl ...
- 「洛谷3870」「TJOI2009」开关【线段树】
题目链接 [洛谷] 题解 来做一下水题来掩饰ZJOI2019考炸的心情QwQ. 很明显可以线段树. 维护两个值,\(Lazy\)懒标记表示当前区间是否需要翻转,\(s\)表示区间还有多少灯是亮着的. ...
随机推荐
- VMware桥接模式连接局域网和互联网
第一步:确认本地网关地址 第二步选择桥接模式: 我比较幸运,桥接到"自动",就已经连接成功.不用逐个试错. 修改 ifcfg-ens33 和 新建 ifcfg-br0 [root@ ...
- 彻彻底底地理解TCP三次握手和四次挥手的全部过程
三次握手 我们先提出一些问题,但是我们暂且不回答这些问题,下面我会尽我所能详尽地讲解TCP的三次握手过程,然后看完你可以在评论区留下你对问题的答案,我们可以一起探讨. 为什么要握手 为什么是三次而不是 ...
- 关于 Intel CPU 和Iris Xe Graphics的报告问题
关于 Intel CPU 和Iris Xe Graphics的报告问题 有些用户报告了一些技术问题,这里有更多的信息和如何解决. Intel 11th CPU & Iris Xe Graphi ...
- Hello world.java
Hello world 1.随便新建一个文件夹,存放源代码 2.新建一个Java文件 文件后缀名为.java Hello.java [注意点]系统可能显示没有后缀名,我们需要手动打开 3.编写代码 p ...
- 同步gitlab与github
1.找到setting 2.找到左下方的developer setting 3.按标好的数字依次执行 4.填写note并勾选repo 5.在最左下方勾选 6.保存生成的新的token到其他地方,之后你 ...
- 【Android】安卓中的存储
[Android]安卓中的存储 1.存储在App内部 最简单的一种.在尝试过程中发现,手机中很多文件夹都没有权限读写.我们可以将我们需要写的文件存放到App中的files文件夹中,当然我们有权限在整个 ...
- [开发笔记usbTOcan]软件需求分析和软件架构设计
前面文章进行了系统分析和系统架构设计,手工焊接了一个板子,集合EK-TMC123GXL开发板(请忽略焊接技术) SWE.1 | 软件需求分析 软件需求分析过程的目的是将系统需求的软件相关部分转化为一组 ...
- 搭服务器之centos-ipv6源--配置各虚拟机系统的ipv6网络安装源。
在2g内存的台式机里安装了三台虚拟机,跑起来好可以,就是swap用的比较多,图见上一篇随笔.现在平台基本有了,自己笔记本算总控,实验室台式机跑着4台机器(一实三虚),加上一台服务器,可以做很多事情了, ...
- 一起看看MySQL中的隐藏列
摘要:在mysql的多版本并发控制mvcc中,我们知道mysql中存在一些隐藏列,例如行标识.事务ID.回滚指针等,不知道大家是否和我一样好奇过,要怎样才能实际地看到这些隐藏列的值呢? 本文分享自华为 ...
- vue学习7-v-show和v-if
1. v-show:这个是一次性会把所有的都渲染出来,然后通过简单的切换display值来修改是否需要被渲染.所以在需要频繁切换的情况下推荐使用.v-show不能在template标签上使用. 2. ...