由于太过SB,懒得写简要题意了。。。
题解:
不难发现我们可以直接考虑 能不能直接走到 然后 DP即可。
最开始把题目看错成距离直线距离不超过 了,我Splay维护动态凸包都写完了艹。。
线段的话也是非常简单,考虑一个不在圆 内部的点,它显然会限制 向后连出去的点的极角范围。
于是维护这个范围即可,然而我的维护方式过于SB导致写挂了,感觉std的方法还挺好的,这里记一下。
容易注意到 允许向后连出的范围是所有点限制出的范围的交,并且每个点单独造成的限制弧度严格小于 。
维护一个基准向量,记录 表示我们允许 连出去的边的极角在基准向量 的弧度范围中,这样维护比较简单。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define db double
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get_integer(){
char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}
}using namespace IO;
using std::cerr;
using std::cout;
cs int N=2e3+7;
cs db eps=1e-7,PI=acos(-1);
struct Pnt{
db x,y;Pnt(){}Pnt(db _x,db _y):x(_x),y(_y){}
friend Pnt operator+(cs Pnt &a,cs Pnt &b){return Pnt(a.x+b.x,a.y+b.y);}
friend Pnt operator-(cs Pnt &a,cs Pnt &b){return Pnt(a.x-b.x,a.y-b.y);}
friend db operator*(cs Pnt &a,cs Pnt &b){return a.x*b.y-b.x*a.y;}
friend db dot(cs Pnt &a,cs Pnt &b){return a.x*b.x+a.y*b.y;}
db len()cs{return sqrt(x*x+y*y);}
db ang()cs{return atan2(y,x);}
};
int n,d;
Pnt p[N];
int dp[N];
struct rng{double l,r,dir;};
rng pr[N][N],sf[N][N];
double adj(double x){
while(x<-PI-eps)x+=2*PI;
while(x>PI+eps)x-=2*PI;
return x;
}
rng calc(cs Pnt &p,cs Pnt &q){
db dlt=adj(asin(d/(p-q).len()));
db rad=atan2(q.y-p.y,q.x-p.x);
return {-dlt,dlt,rad};
}
rng merge(rng a,rng b){
if(a.dir>PI+PI)return b;
if(b.dir>PI+PI)return a;
db dlt=adj(b.dir-a.dir);
db l=b.l+dlt,r=b.r+dlt;
a.l=std::max(a.l,l);
a.r=std::min(a.r,r);
return a;
}
bool in(cs rng &a,double rad){
if(a.dir>PI+PI)return true;
rad=adj(rad-a.dir);
return a.l-eps<rad&&rad<a.r+eps;
}
bool judge(int i,int j){
return in(pr[i][j+1],(p[j]-p[i]).ang())&&
in(sf[j][i-1],(p[i]-p[j]).ang());
}
void Main(){
n=gi(),d=gi();
for(int re i=1;i<=n;++i)
p[i].x=gi(),p[i].y=gi();
for(int re i=1;i<=n;++i){
sf[i][i]=(rng){0,PI+PI,1e9};
pr[i][i]=(rng){0,PI+PI,1e9};
for(int re j=i+1;j<=n;++j){
if((p[i]-p[j]).len()<d+eps)
sf[i][j]=sf[i][j-1];
else
sf[i][j]=merge(sf[i][j-1],calc(p[i],p[j]));
}
for(int re j=i-1;j;--j){
if((p[i]-p[j]).len()<d+eps)
pr[i][j]=pr[i][j+1];
else
pr[i][j]=merge(pr[i][j+1],calc(p[i],p[j]));
}
}dp[1]=1;
for(int re i=2;i<=n;++i){
dp[i]=1e9;
for(int re j=1;j<i;++j)
if(judge(i,j))dp[i]=std::min(dp[i],dp[j]+1);
}
cout<<dp[n]<<"\n";
}
inline void file(){
#ifdef zxyoi
freopen("kingdom.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
freopen("kingdom.in","r",stdin);
freopen("kingdom.out","w",stdout);
#endif
#endif
}signed main(){file();Main();return 0;}