[背景]
抓紧时间写完!
今天耗费VHOS心力最多的是这道虚伪的题目,首先必须要吐槽一下:为什么WIFI设置这么坑!!!!
好的,由于我们上的是分治,所以我优先选择了二分来做这道题,同时给出周神的递增版本。
[题目]
题目描述
一条街道安装WIFI,需要放置M个路由器。整条街道上一共有N户居民,分布在一条直线上,每一户居民必须被至少一台路由器覆盖到。现在的问题是所有路由器的覆盖半径是一样的,我们希望用覆盖半径尽可能小的路由器来完成任务,因为这样可以节省成本。
输入格式
输入文件第一行包含两个整数M和N,以下N行每行一个整数Hi表示该户居民在街道上相对于某个点的坐标。
输出格式
输出文件仅包含一个数,表示最小的覆盖半径,保留一位小数。
样例数据
input
2 3
1
3
10
output
1.0
数据规模与约定
时间限制:1s
1s
空间限制:256MB
256MB
注释
对于60%的数据,有1 ≤ N, M ≤ 100,-1000 ≤ Hi ≤ 1000; 对于100%的数据,有1 ≤ N, M ≤ 100000,-10000000 ≤ Hi ≤ 10000000。
[二分的分析]
很显然这道题要枚举最合适的路由器范围直径(然后除以二出答案)
而枚举的任务就交给枚举的代码了;
以上是程序的准备模块
很好,二分的主体完成了,现在只要判断这个直径值成不成立就行了;
虚伪虚伪虚伪虚伪,严重怀疑网络稳定性
[code]
[二分]
#include<bits/stdc++.h>
const int maxn=1<<17;
int lc[maxn]={};
int home=0,max_wifi=0;
int ip(void)
{
int sign=1,num=0;
char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-')
sign=-1;
for(;c>='0'&&c<='9';c=getchar())
num=(num<<1)+(num<<3)+c-'0';
return num*sign;
}
bool check(int size)
{
int wifi=0;
int left=1,right=1;
while(right<=home)
{
while(lc[right]-lc[left]<=size&&right<=home)
right++;
left=right;
wifi++;
}
if(wifi<=max_wifi)
return true;
else
return false;
}
int main(void)
{
max_wifi=ip();
home=ip();
for(int i=1;i<=home;i++)
{
lc[i]=ip();
}
std::sort(lc+1,lc+home+1);
int left=-1<<22;
int right=1<<22;
int mid=0;
while(left+1<right)
{
mid=(left+right)>>1;
if(check(mid))
right=mid;
else
left=mid;
}
if(check(left))
printf("%.1f",left*1.0/2);
else
printf("%.1f",right*1.0/2);
return 0;
}
[递增]{周神提供}
#include<bits/stdc++.h>
using namespace std;
int a[1002003],n,m;
#define C getchar()-48
inline int read()
{
int s=0,t=1,k=C;
for (;k>9||k<0;k=C) if (k==-3) t=-1;
for (;k>=0&&k<=9;k=C) s=(s<<1)+(s<<3)+k;
return s*t;
}
inline int che(int k)
{
int t=0,l=1,r=1;
while (r<=n)
{
while (a[r]-a[l]<=k&&r<=n) r++;
l=r,++t;
}
if (t<=m) return 1;
return 0;
}
int main(void)
{
cin>>m>>n;
for (int i=n;i;--i)
a[i]=read();
sort(a+1,a+n+1);
int k=a[n]-a[1];
for (int i=log2(k);i>=0;--i)
if (k-(1<<i)>0&&che(k-(1<<i))) k-=1<<i;
printf("%.1f",k*1.0/2);
return 0;
}