由於太過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;}