题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=2280

https://loj.ac/problem/2159

题解

显然对于一段的 \(q_i\),就是这一段的最小圆覆盖的圆心。

考虑二分一个 \(mid\),表示每一段的最小圆覆盖的半径的最大值。

然后我们可以在点序列上从开头一直往后走,直到半径大于 \(mid\),就算上一段并重新开始记录最小圆覆盖,然后把总的段数与 \(m\) 比较。

看上去没什么问题啊,时间复杂度 \(O(n\log eps^{-1})\),但是怎么 BZOJ 上时间限制有 300s,比紫荆花之恋还长啊。

等等,好像最小圆覆盖的时间复杂度的正确性需要把整个序列都打乱啊。不好,这样就不能保证了题目中要的连续的一段了。

那么我们想一想怎么更正这个算法。

每次从当前的起点 \(i\) 向右扩展的时候,可以二分一个 \(mid\),然后把 \(i..mid\) 这一段求一下最小圆覆盖?不对不对,这样二分的话,时间复杂度是 \(O(nm\log n\log eps^{-1})\)。

但是我们想要的是,对于长度为 \(l\) 的一段,能够通过 \(l\log l\) 把它二分出来,而不是 \(n\log n\)。

所以这里有一个小 trick,可以一个一个测试 \(i\) 右边 \(1, 2, 4, 8, \cdots\) 位之间的每一段满不满足条件。这样倍增下去,最后我们就可以得到一个信息 \(2^k-1 \leq l < 2^k-1\)。然后我们就可以在这个范围内二分了。这样因为每一次二分的 \(mid\) 都是和 \(l\) 在同一级别的,所以复杂度为 \(O(l\log l)\)。

这样就可以在 \(O(n\log l\log eps^{-1})\) 的时间复杂度内 AC 了。


下面是代码。如上文所属,这个代码的时间复杂度为 \(O(n\log l \log eps^{-1})\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
} const int N = 100000 + 7;
const double eps = 1e-8; int n, m, cnt; inline int dcmp(const double &x) { return fabs(x) <= eps ? 0 : (x < 0 ? -1 : 1); }
struct Point {
double x, y;
inline Point(const double &x = 0, const double &y = 0) : x(x), y(y) {}
} a[N], b[N], ans[N]; inline double dist(const Point &a, const Point &b) { return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }
inline Point get_C(const Point &p1, const Point &p2, const Point &p3) {
double c1 = (p1.x * p1.x + p1.y * p1.y) - (p2.x * p2.x + p2.y * p2.y), a1 = 2 * (p1.x - p2.x), b1 = 2 * (p1.y - p2.y);
double c2 = (p2.x * p2.x + p2.y * p2.y) - (p3.x * p3.x + p3.y * p3.y), a2 = 2 * (p2.x - p3.x), b2 = 2 * (p2.y - p3.y);
double x = (b1 * c2 - b2 * c1) / (a2 * b1 - a1 * b2), y = (a1 * c2 - a2 * c1) / (a1 * b2 - a2 * b1);
return Point(x, y);
} inline std::pair<Point, double> calc(int L, int R) {
int n = 0;
for (int i = L; i <= R; ++i) b[++n] = a[i];
std::random_shuffle(b + 1, b + n + 1);
Point O = b[1];
double r = 0;
for (int i = 2; i <= n; ++i) if (dcmp(dist(O, b[i]) - r) > 0) {
O = b[i], r = 0;
for (int j = 1; j < i; ++j) if (dcmp(dist(O, b[j]) - r) > 0) {
O = Point((b[i].x + b[j].x) / 2, (b[i].y + b[j].y) / 2), r = dist(b[i], O);
for (int k = 1; k < j; ++k) if (dcmp(dist(O, b[k]) - r) > 0) {
O = get_C(b[i], b[j], b[k]);
r = dist(b[i], O);
}
}
}
return std::make_pair(O, r);
} inline bool check(const double &mid) {
cnt = 0;
int now = 1;
while (now <= n) {
int i = 1;
for (; now + (1 << i) - 1 <= n; ++i)
if (calc(now, now + (1 << i) - 1).se - mid > eps) break;
int l = now + (1 << (i - 1)) - 1, r = std::min(now + (1 << i) - 2, n);
while (l < r) {
int mid2 = (l + r + 1) >> 1;
if (calc(now, mid2).se - mid < eps) l = mid2;
else r = mid2 - 1;
}
ans[++cnt] = calc(now, l).fi, now = l + 1;
}
return cnt <= m;
} inline void work() {
double l = 0, r = 2000000;
while (r - l >= eps) {
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
printf("%.8lf\n", r);
check(r);
printf("%d\n", cnt);
for (int i = 1; i <= cnt; ++i) printf("%.8lf %.8lf\n", ans[i].x, ans[i].y);
} inline void init() {
srand(time(0) + (ull)new char);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%lf%lf", &a[i].x, &a[i].y);
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

BZOJ2280 [Poi2011]Plot 二分+倍增+最小圆覆盖的更多相关文章

  1. 【bzoj2280】[Poi2011]Plot 二分+倍增+二分+最小圆覆盖

    题目描述 给出一系列点p_1, p_2, ... , p_n,将其分成不多余m个连续的段,第i段内求一个点q_i,使得q_i到这段内点的距离的最大值的最大值最小 输入 第一行,n m下面n行,每行两个 ...

  2. BZOJ2280 [Poi2011]Plot

    恩..这题真是sxbk 我们先二分答案,然后判断答案是否满足要求 判断方法是二分当前段的长度一直做到底,当然我们可以用倍增这样快一点,直接随机增量就可以了 然后就是卡常..... 然后就是卡精度QAQ ...

  3. 【做题】POI2011R1 - Plot——最小圆覆盖&倍增

    原文链接 https://www.cnblogs.com/cly-none/p/loj2159.html 题意:给出\(n\)个点,你需要按编号将其划分成不超过\(m\)段连续的区间,使得所有每个区间 ...

  4. 洛谷P4586 [FJOI2015]最小覆盖双圆问题(最小圆覆盖)

    题面 传送门 前置芝士 最小圆覆盖 题解 我们按照\(x\)坐标排序,然后二分中间点,把点分成左右两边,对两边都做一个最小圆覆盖,那么半径大一点的那个就是答案了.然后对半径大的那一边继续二分就行了 然 ...

  5. 【BZOJ-1336&1337】Alie最小圆覆盖 最小圆覆盖(随机增量法)

    1336: [Balkan2002]Alien最小圆覆盖 Time Limit: 1 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1573   ...

  6. Bzoj 1336&1337 Alien最小圆覆盖

    1336: [Balkan2002]Alien最小圆覆盖 Time Limit: 1 Sec  Memory Limit: 162 MBSec  Special Judge Submit: 1473  ...

  7. hdu3007Buried memory(最小圆覆盖)

    链接 普通的暴力复杂度达到O(n^4),对于这题肯定是不行的. 解法:随机增量算法 参考http://www.2cto.com/kf/201208/149602.html algorithm:A.令C ...

  8. [BZOJ 3564] [SHOI2014] 信号增幅仪 【最小圆覆盖】

    题目链接:BZOJ - 3564 题目分析 求最小椭圆覆盖,题目给定了椭圆的长轴与 x 轴正方向的夹角,给定了椭圆长轴与短轴的比值. 那么先将所有点旋转一个角度,使椭圆长轴与 x 轴平行,再将所有点的 ...

  9. [BZOJ 1336] [Balkan2002] Alien最小圆覆盖 【随机增量法】

    题目链接:BZOJ - 1336 题目分析 最小圆覆盖有一个算法叫做随机增量法,看起来复杂度像是 O(n^3) ,但是可以证明其实平均是 O(n) 的,至于为什么我不知道= = 为什么是随机呢?因为算 ...

随机推荐

  1. 8.为什么IntelliJ IDEA首次加载比较慢

    double shift 很快,是有缓存,和快速索引 这面这二个文件,配置会缓存:会越来越在,

  2. Cocoapods组件化之搭建组件化项目框架

    一,概述 随着公司业务需求的不断迭代发展,工程的代码量和业务逻辑也越来越多,原始的开发模式和架构已经无法满足我们的业务发展速度了,这时我们就需要将原始项目进行一次重构大手术了.这时我们应该很清晰这次手 ...

  3. 十二 windows临界区,其他各种mutex

    一.windows临界区 类似于互斥量 == 临界区. 二.多次进入临界区 进入临界区(加锁): 离开临界区(解锁): 同一个线程中windows中相同临界区变量代表的临界区进入(entercirti ...

  4. Nginx负载均衡与反向代理—《亿级流量网站架构核心技术》

    当我们的应用单实例不能支撑用户请求时,此时就需要扩容,从一台服务器扩容到两台.几十台.几百台.然而,用户访问时是通过如http://www.XX.com的方式访问,在请求时,浏览器首先会查询DNS服务 ...

  5. New Relic性能监控(一)概览

    New Relic性能监控(一)概览 2018-04-12 琅琊书生 本系列文章基于公司使用New Relic的经验,鉴于国内较少有这方面的文章,因此把我工作中了解到的知识分享给大家,希望可以给需要的 ...

  6. Jsoup学习和使用

    我们先看一下百度百科简介 它是java的HTML解析器 用HttpClient获取到网页后 具体的网页提取需要的信息的时候 ,就用到Jsoup,Jsoup可以使用强大的类似选择器,来获取需要的数据. ...

  7. NuGet-Doc:承载自己的 NuGet 源

    ylbtech-NuGet-Doc:承载自己的 NuGet 源 1.返回顶部 1. 可能希望将包仅发布到有限受众(例如,组织或工作组),而不是将其公开发布. 此外,一些公司可能希望限制其开发人员可以使 ...

  8. 详细理解JS中的继承

    正式说继承之前,有两个相关小点: JS只支持实现继承,即继承实际的方法,不支持接口继承(即继承方法的签名,但JS中函数没签名) 所有对象都继承了Object.prototype上的属性和方法. 说继承 ...

  9. Oracle 数据库优化

    Oracle 数据库优化 参考网址

  10. 夜雨惊风 Linux下卸载openjdk,安装jdk

    1.查看java版本 1 2 3 4 [root@CFDB2 ~]# java -version openjdk version "1.8.0_171" OpenJDK Runti ...