题目描述

给出一系列点p_1, p_2, ... , p_n,将其分成不多余m个连续的段,第i段内求一个点q_i,使得q_i到这段内点的距离的最大值的最大值最小

输入

第一行,n m
下面n行,每行两个整数,表示p_i的x y坐标
1<=m<=n<=100000
坐标范围[-1000000,1000000] 0<p,q,r<=150,输入中至少包含一个’N’

输出

第一行,q_i到这段内点的距离的最大值的最大值的最小值
第二行,分成的段数k
下面k行,每行两个实数,表示q_k的x y坐标

All the real numbers should be printed with at most 15 digits after the decimal point.

样例输入

7 2
2 0
0 4
4 4
4 2
8 2
11 3
14 2

样例输出

3.00000000
2
2.00000000 1.76393202
11.00000000 1.99998199


题解

二分+倍增+二分+最小圆覆盖

最大值最小,一眼二分答案。

考虑怎么判定:取前任意个点跑最小圆覆盖,直到半径大于mid为止,最后看分成段的数目是否超过m即可。

然而这样暴力跑是不行的,需要优化这个过程;同时直接再二分也是不可取的,因为二分的区间长度是满的,最坏情况下每段长度都为1,每段都需要$O(n\log n)$的时间来找,GG。

所以需要让求最小圆覆盖的点数只与每段长有关。考虑倍增,处理出第一个$j$,满足$2^j$个不满足条件。然后在$2^{j-1}$到$2^j$之间二分处理即可。这样第一部分时间复杂度为$O(len)$,第二部分时间复杂度为$O(len\log len)$,与n无关,所以可以满足时间要求。

因此总的时间复杂度为$O(n\log^2n)$,然而常数巨大。。。所以才给300s。。。

最小圆覆盖的求法参见 http://www.cnblogs.com/GXZlegend/p/7467029.html

CQzhangyu说卡精度,然而没看出来= = 1A了

#include <cstdio>
#include <algorithm>
#define N 100010
#define eps 1e-15
using namespace std;
int n , m , id[N] , tot;
double mid , x[N] , y[N] , ansx[N] , ansy[N];
inline double squ(double x)
{
return x * x;
}
bool check(int lp , int rp , double &vx , double &vy)
{
int i , j , k , len = rp - lp + 1;
double px = 0 , py = 0 , r = 0 , x1 , x2 , x3 , y1 , y2 , y3;
for(i = lp ; i <= rp ; i ++ ) id[i - lp + 1] = i;
random_shuffle(id + 1 , id + len + 1);
for(i = 1 ; i <= len ; i ++ )
{
if(squ(px - x[id[i]]) + squ(py - y[id[i]]) > r + eps)
{
px = x[id[i]] , py = y[id[i]] , r = 0;
for(j = 1 ; j < i ; j ++ )
{
if(squ(px - x[id[j]]) + squ(py - y[id[j]]) > r + eps)
{
px = (x[id[i]] + x[id[j]]) / 2 , py = (y[id[i]] + y[id[j]]) / 2 , r = (squ(x[id[i]] - x[id[j]]) + squ(y[id[i]] - y[id[j]])) / 4;
if(r > mid * mid + eps) return 0;
for(k = 1 ; k < j ; k ++ )
{
if(squ(px - x[id[k]]) + squ(py - y[id[k]]) > r + eps)
{
x1 = x[id[i]] , x2 = x[id[j]] , x3 = x[id[k]];
y1 = y[id[i]] , y2 = y[id[j]] , y3 = y[id[k]];
px = (x1 * x1 * (y2 - y3) + x2 * x2 * (y3 - y1) + x3 * x3 * (y1 - y2) - (y1 - y2) * (y2 - y3) * (y3 - y1)) / (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2;
py = ((x1 - x2) * (x2 - x3) * (x3 - x1) - y1 * y1 * (x2 - x3) - y2 * y2 * (x3 - x1) - y3 * y3 * (x1 - x2)) / (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2;
r = squ(px - x1) + squ(py - y1);
if(r > mid * mid + eps) return 0;
}
}
}
}
}
}
vx = px , vy = py;
return 1;
}
bool judge()
{
int i , len , last , l , r , mid;
bool flag;
double tmpx , tmpy;
tot = 0;
for(i = 1 ; i <= n ; i = last + 1)
{
if(tot == m) return 0;
flag = 0;
for(len = 1 ; !flag ; len <<= 1)
{
if(!check(i , min(i + len - 1 , n) , tmpx , tmpy))
{
flag = 1;
break;
}
else if(i + len - 1 >= n)
{
tot ++ , ansx[tot] = tmpx , ansy[tot] = tmpy;
return 1;
}
l = i + len;
}
r = min(i + len - 1 , n) , last = l - 1;
while(l <= r)
{
mid = (l + r) >> 1;
if(check(i , mid , tmpx , tmpy)) last = mid , l = mid + 1;
else r = mid - 1;
}
check(i , last , tmpx , tmpy) , tot ++ , ansx[tot] = tmpx , ansy[tot] = tmpy;
}
return 1;
}
int main()
{
srand(20011011);
int i , cnt = 50;
double l = 0 , r = 2e6;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ ) scanf("%lf%lf" , &x[i] , &y[i]);
while(cnt -- )
{
mid = (l + r) / 2;
if(judge()) r = mid;
else l = mid;
}
printf("%.15lf\n" , r);
mid = r , judge();
printf("%d\n" , tot);
for(i = 1 ; i <= tot ; i ++ ) printf("%.15lf %.15lf\n" , ansx[i] , ansy[i]);
return 0;
}

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

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

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2280 https://loj.ac/problem/2159 题解 显然对于一段的 \(q_i ...

  2. BZOJ2280 [Poi2011]Plot

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

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

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

  4. ACM-ICPC Beijing 2016 Genius ACM(倍增+二分)

    描述 给定一个整数 M,对于任意一个整数集合 S,定义“校验值”如下: 从集合 S 中取出 M 对数(即 2∗M 个数,不能重复使用集合中的数,如果 S 中的整 数不够 M 对,则取到不能取为止),使 ...

  5. 【题解】我也不是B ifrog 1112 二分 倍增

    题目传送门:http://ifrog.cc/acm/problem/1112 神奇的倍增二分,长见识了,在此做个记录,分享给大家. 懒得写题解了,直接转YJQ的:http://ifrog.cc/acm ...

  6. poj3579 二分套二分

    和poj3685类似,都是二分答案然后在判断时再二分 这题的内层二分可以用stl代替 /* 二分套二分,思路:升序排序数据,先二分答案x进行判断,判断时枚举每个元素,二分找到和其之差小于等于x的所有值 ...

  7. LibreOJ #2006. 「SCOI2015」小凸玩矩阵 二分答案+二分匹配

    #2006. 「SCOI2015」小凸玩矩阵 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  8. POJ-3579 Median---二分第k大(二分套二分)

    题目链接: https://cn.vjudge.net/problem/POJ-3579 题目大意: 求的是一列数所有相互之间差值的序列的最中间的值是多少. 解题思路: 可以用二分套二分的方法求解第m ...

  9. poj 3579 Median 二分套二分 或 二分加尺取

    Median Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5118   Accepted: 1641 Descriptio ...

随机推荐

  1. Nginx+proxy实现简单的负载均衡

    环境说明:操作系统centos6.6 64位web操纵系统是:web1=192.168.10.10(LAMP) web2=192.168.10.11(LNMP),这里只是测试nginx实现负载均衡效果 ...

  2. 用TreeView控件遍历磁盘目录

    实现效果: 知识运用: ListView控件中Items集合的Add方法  TteeView控件中Nodes集合的Add方法 实现代码: private void Form1_Load(object ...

  3. fflush - 刷新一个流

    SYNOPSIS 总览 #include <stdio.h> int fflush(FILE *stream); DESCRIPTION 描述 函数 fflush 强制在所给的输出流或更新 ...

  4. c++question 005 c++中转义字符有哪些?

    (1)'\a'  注意,这里不再是两个字符\ 和 a 而是表达了一个具体的含义是,蜂鸣一声 (2)'\n' 换行,这里不再是两个字符\ 和 n 而是表达了一个具体的含义是,相当于 endl (3)'\ ...

  5. HTML5页面元素中的文本最快速替换replace()方法

    $.ajax({ type:"get", url:spanUrl, dataType:'jsonp', jsonpCallback:'jsonp',//jsonp数据,需要数据库提 ...

  6. 读书笔记3(Teamwork)

    今天我阅读了<构建之法>的第四章——两人合作,它主要讲述了在两人合作进行项目时与单人作业时的区别与不同,其中最重要的就是代码规范.代码规范:我们写的代码虽然是电脑运行,但是最终还是给人看的 ...

  7. python---列表(list)基本操作

    列表基本操作:增.删.查.改等其他操作 创建列表: list1 = ["a","b","c","d"] name_lis ...

  8. makefile学习(1)

    GNU Make / Makefile 学习资料 GNU Make学习总结(一) GNU Make学习总结(二) 这篇学习总结,从一个简单的小例子开始,逐步加深,来讲解Makefile的用法. 最后用 ...

  9. 机顶盒demux的工作原理

    在机顶盒中demux部分相对来说是比较复杂的部分,对于机顶盒软件开发的新手来说通常在这里会遇到一些困难,今天特意研究了一下驱动层代码,有一点自己的理解,因此写下来记录一下学习过程. 机顶盒中数据是如何 ...

  10. A计划 hdu2102(BFS)

    A计划 hdu2102 可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸的她再一次面临生命的考验.魔王已经发出消息说将在T时刻吃掉公主,因为他听信谣言说吃公主的肉也能长生不老.年迈的国 ...