LOJ #2159. 「POI2011 R1」Plot
阿新 • • 發佈:2018-12-30
好難寫啊!
這題如果保證資料隨機,那麼可以直接跑一個最小圓覆蓋,先二分半徑,再貪心覆蓋。
但是出題人顯然不會這麼善良。
於是就可以倍增,\(1,2,4,8,16...\),這樣嘗試長度,找到最大可行二進位制長度(即最高位)後,再逐位確定。
複雜度\(O(nlog^2(n))\)
但是寫完之後又被卡了精度,改隨機數種子才可以過。
#include <bits/stdc++.h> using namespace std; const int N=100010; typedef double ld; const ld EPS=1e-8; struct point{ ld x,y; ld distance(){ return sqrt(x*x+y*y); } point operator *(const ld &z) const{ return {z*x,z*y}; } point operator /(const ld &z) const{ return {x/z,y/z}; } ld operator ^(const point &_) const{ return x*_.x+y*_.y; } ld operator *(const point &_) const{ return x*_.y-y*_.x; } point operator +(const point &_) const{ return {x+_.x,y+_.y}; } ld sqr() const{ return x*x+y*y; } point operator -(const point &_) const{ return {x-_.x,y-_.y}; } point rotate(const ld &alpha) const{ ld tc=cos(alpha),ts=sin(alpha); return {x*tc-y*ts,x*ts+y*tc}; } point normal() const{ return {-y,x}; } }a[N],c[N]; struct line{ point x,y; point generate(const ld &c) const{ return x+y*c; } point cross(const line &u) const{ ld s1=y*u.y; ld s2=u.y*(x-u.x); //cerr<<s1<<" "<<s2<<" "<<u.y.x<<" "<<u.y.y<<endl; //cerr<<x.x<<" "<<x.y<<" "<<y.x<<" "<<y.y<<endl; return generate(s2/s1); } }; struct cir{ point o; ld r; bool in(const point &d) const{ return (o-d).sqr()<=r; } }; bool rec,re; int n,m; int num; point out[N]; cir solve(const point &x,const point &y,const point &z){ //line l1{(x+y)/2,(x-y).rotate(M_PI_2)}; //line l2{(y+z)/2,(z-y).rotate(M_PI_2)}; line l1{(x+y)/2,(x-y).normal()}; line l2{(y+z)/2,(z-y).normal()}; if (abs(l1.y*l2.y)<EPS){ ld len=max(max((x-y).sqr(),(x-z).sqr()),(y-z).sqr()); if (len==(x-y).sqr()){ return {(x+y)/2,sqrt(len)/2}; } if (len==(x-z).sqr()){ return {(x+z)/2,sqrt(len)/2}; } return {(y+z)/2,len/2}; } point tmp=l1.cross(l2); return {tmp,(tmp-x).sqr()}; } ld check(int l,int r){ if (r-l+1==1){ if (re) out[++num]=a[l]; return 0; } for (int i=l; i<=r; ++i) c[i]=a[i]; random_shuffle(c+l,c+r+1); cir tmp={c[l],0}; for (int i=l+1; i<=r; ++i){ if (tmp.in(c[i])) continue; tmp={c[i],0}; for (int j=l; j<i; ++j) if (!tmp.in(c[j])){ tmp={(c[i]+c[j])/2,(c[i]-c[j]).sqr()/4}; for (int k=l; k<j; ++k) if (!tmp.in(c[k])){ //cerr<<i<<" "<<j<<" "<<k<<endl; //cerr<<c[i].x<<" "<<c[i].y<<endl; //cerr<<c[j].x<<" "<<c[j].y<<endl; //cerr<<c[k].x<<" "<<c[k].y<<" "<<l<<" "<<r<<endl; tmp=solve(c[i],c[j],c[k]); } } } if (re){ out[++num]=tmp.o; } return tmp.r; } int getnext(const int &x,const ld &mid){ int i; for (i=2; x+i-1<=n; i<<=1) if (check(x,x+i-1)>mid*mid) break; for (int j=(i>>=1); j; j>>=1) if (x+i+j-1<=n&&check(x,x+i+j-1)<=mid*mid) i+=j; if (rec){ re=1; check(x,x+i-1); re=0; } return x+i; } bool maybe(const ld &mid){ //cerr<<"maybe:"<<mid<<endl; int rest=m; for (int i=1; i<=n; i=getnext(i,mid)) if (--rest<0) return 0; //cerr<<"SUCC"<<endl; return 1; } int main(){ srand(19260817); scanf("%d%d",&n,&m); for (int i=1; i<=n; ++i) scanf("%lf%lf",&a[i].x,&a[i].y); ld ret=-1; for (ld l=0,r=3e6,mid=(l+r)/2; l+EPS<r; mid=(l+r)/2) if (maybe(mid)) r=ret=mid; else l=mid; cout<<fixed<<setprecision(10); cout<<ret<<endl; rec=1; maybe(ret); cout<<num<<endl; for (int i=1; i<=num; ++i) cout<<out[i].x<<" "<<out[i].y<<'\n'; }