首先可以二分答案
a
n
s
ans
ans。
然后再从左往右在最小圆半径
<
=
a
n
s
<=ans
<=ans的情况下尽量多分点在同一组。
因为最小圆覆盖需要随机,所以不能直接从左往右加。
这个过程也不能二分,因为
c
h
e
c
k
check
check的复杂度是
O
(
二
分
答
案
)
O(二分答案)
O(二分答案)的。
但是发现我们有总答案
=
n
=n
=n
于是可以用倍增代替二分,那么我们
c
h
e
c
k
check
check的总复杂度是
O
(
答
案
log
n
)
O(答案\log n)
O(答案logn)的。
注意这个输出方案极度卡精。
A C C o d e \mathrm{AC \ Code} AC Code
#include<bits/stdc++.h>
#define maxn 100005
#define Pt Point
#define Ct const
#define db double
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define eps 1e-20
using namespace std;
int n,m;
inline db sqr(Ct db &x){ return x*x; }
struct Pt{
db x,y;Pt(db x=0,db y=0):x(x),y(y){}
Pt operator +(Ct Pt &B)Ct{ return Pt(x+B.x,y+B.y); }
Pt operator -(Ct Pt &B)Ct{ return Pt(x-B.x,y-B.y); }
Pt operator *(Ct db &B)Ct{ return Pt(x*B,y*B); }
Pt operator /(Ct db &B)Ct{ return Pt(x/B,y/B); }
db operator *(Ct Pt &B)Ct{ return x*B.y-y*B.x; }
db Len()Ct{ return sqr(x)+sqr(y); }
Pt Rotate90(){ return Pt(y,-x); }
}P[maxn],O[maxn],rP[maxn];
int cnt;db r[maxn];
Pt Intersec(Ct Pt &p1,Ct Pt &v1,Ct Pt &p2,Ct Pt &v2){
db t = (p2 - p1) * v2 / (v1 * v2);
return p1 + (v1 * t);
}
db cal(int L,int R,Pt &O,db &r){
random_shuffle(&P[L],&P[R+1]);
r=0;
rep(i,L,R) if((P[i]-O).Len()>r){
O=P[i],r=0;
rep(j,L,i-1) if((P[j]-O).Len()>r){
O=(P[i]+P[j])/2,r=(P[i]-P[j]).Len()/4;
rep(k,L,j-1) if((P[k]-O).Len()>r){
if(fabs((P[i]-P[j])*(P[i]-P[k]))>1e-8)
O=Intersec((P[i]+P[j])/2,(P[i]-P[j]).Rotate90(),(P[i]+P[k])/2,(P[i]-P[k]).Rotate90());
else{
db dij = (P[i]-P[j]).Len() , dik = (P[i] - P[k]).Len() , djk = (P[j] - P[k]).Len();
if(dij > dik && dij > djk) O=(P[i]+P[j])/2;
if(dik > dij && dik > djk) O=(P[i]+P[k])/2;
if(djk > dij && djk > dik) O=(P[j]+P[k])/2;
}
r=(P[i]-O).Len();
}
}
}
rep(i,L,R) P[i]=rP[i];
return r;
}
bool check(db d){
cnt = 0;
for(int i=1,j,p;i<=n;i=i+p){
if(++cnt > m) return 0;
j=2,p=0;
for(;i+j-1<=n;j<<=1) if(cal(i,i+j-1,O[cnt],r[cnt]) > d) break;
for(int k=j>>1;k;k>>=1) if(i+p+k-1<=n && cal(i,i+p+k-1,O[cnt],r[cnt]) <= d) p+=k;
cal(i,i+p-1,O[cnt],r[cnt]);
}
return 1;
}
int main(){
scanf("%d%d",&n,&m);
rep(i,1,n) scanf("%lf%lf",&P[i].x,&P[i].y),rP[i]=P[i];
db L=0,R=1e14,mid;
for(int stp=0;stp<=100;stp++){
mid=(L+R)*0.5;
if(check(mid)) R=mid;
else L=mid;
if(R-L < eps) break;
}
mid=(L+R)*0.5;
printf("%.15lf\n",sqrt(mid));
check(mid+1e-3);
printf("%d\n",cnt);
rep(i,1,cnt) printf("%.15lf %.15lf\n",O[i].x,O[i].y);
}