#include<bits/stdc++.h> usingnamespacestd; #define forl(i, l, r) for (int i = l; i <= r; i++) #define forr(i, r, l) for (int i = r; i >= l; i--) #define for1(i, n) for (int i = 1; i <= n; i++) #define fro1(i, n) for (int i = 1; i <= n; i++) #define for0(i, n) for (int i = 0; i < n; i++) #define fro0(i, n) for (int i = 0; i < n; i++) #define meminf(a) memset(a, inf, sizeof(a)) #define mem_1(a) memset(a, -1, sizeof(a)) #define mem0(a) memset(a, 0, sizeof(a)) #define memcp(a,b) memcpy(a,b,sizeof(b)) #define oper(type) bool operator <(const type Y)const #define mp make_pair #define pu_b push_back #define pu_f push_front #define po_b pop_back #define po_f pop_front #define fi first #define se second typedef pair<longlong, longlong> pll; typedefvector<longlong> vll; typedef pair<int, int> pii; typedefunsignedlonglong ull; typedefvector<int> vii; typedefdouble db; typedeflongdouble ldb; typedeflonglong ll; voidin(initializer_list<int*> li){for(auto ptr=li.begin();ptr!=li.end();ptr++)scanf("%d",*ptr);} voidin(initializer_list<ll*> li){for(auto ptr=li.begin();ptr!=li.end();ptr++)scanf("%lld",*ptr);} voidin(initializer_list<db*> li){for(auto ptr=li.begin();ptr!=li.end();ptr++)scanf("%lf",*ptr);} voidout(initializer_list<int> li){auto ti=li.end();ti--;for(auto ptr=li.begin();ptr!=li.end();ptr++)printf("%d%c",*ptr,ptr==ti?'\n':' ');} voidout(initializer_list<ll> li){auto ti=li.end();ti--;for(auto ptr=li.begin();ptr!=li.end();ptr++)printf("%lld%c",*ptr,ptr==ti?'\n':' ');} voidout(initializer_list<db> li){auto ti=li.end();ti--;for(auto ptr=li.begin();ptr!=li.end();ptr++)printf("%f%c",*ptr,ptr==ti?'\n':' ');} voidout(int a,bool ln){printf("%d%c",a,ln?'\n':' ');} voidout(ll a,bool ln){printf("%lld%c",a,ln?'\n':' ');} voidout(db a,int digit,bool ln){printf("%.*f%c",digit,a,ln?'\n':' ');} voidout(ldb a,int digit,bool ln){printf("%.*Lf%c",digit,a,ln?'\n':' ');} voidout0(int a[],int n){for0(i,n)out(a[i],i==n-1);} voidout1(int a[],int n){for1(i,n)out(a[i],i==n);} voidout0(ll a[],int n){for0(i,n)out(a[i],i==n-1);} voidout1(ll a[],int n){for1(i,n)out(a[i],i==n);} intin(int &a,int &b,int &c,int &d){returnscanf("%d%d%d%d",&a,&b,&c,&d);} intin(int &a,int &b,int &c){returnscanf("%d%d%d",&a,&b,&c);} intin(int &a,int &b){returnscanf("%d%d",&a,&b);} intin(ll &a,ll &b,ll &c,ll &d){returnscanf("%lld%lld%lld%lld",&a,&b,&c,&d);} intin(ll &a,ll &b,ll &c){returnscanf("%lld%lld%lld",&a,&b,&c);} intin(ll &a,ll &b){returnscanf("%lld%lld",&a,&b);} intin(ll &a){returnscanf("%lld",&a);} intin(int &a){returnscanf("%d",&a);} intin(char *s){returnscanf("%s",s);} intin(char &c){returnscanf("%c",&c);} intin(db &a){returnscanf("%lf",&a);} intin(ldb &a){returnscanf("%Lf",&a);} voidin0(int a[],int n){for0(i,n)in(a[i]);} voidin1(int a[],int n){for1(i,n)in(a[i]);} voidin0(ll a[],int n){for0(i,n)in(a[i]);} voidin1(ll a[],int n){for1(i,n)in(a[i]);} const db pi = acos(-1); const db eps = 1e-8; intsign(db a){return a < -eps ? -1 : a > eps;} intdb_cmp(db a, db b){ return sign(a-b);} intinmid(db k1,db k2,db k3){return sign(k1-k3)*sign(k2-k3)<=0;}// k3 在 [k1,k2]或[k2,k1] 内 ll inf =0x3f3f3f3f; ll mod = 1e9+7; constint M = 2.1e5; constint N = 2.1e5; /*-----------------------------------head----------------------------------------------*/
structPoint{ db x,y; Point(){} Point(db _x,db _y) : x(_x),y(_y){} Point operator + (const Point &k1) const{return Point(k1.x+x,k1.y+y);} Point operator - (const Point &k1) const{return Point(x-k1.x,y-k1.y);} Point operator * (const db k1) const{return Point(x*k1,y*k1);} Point operator / (const db k1) const{return Point(x/k1,y/k1);} db operator * (const Point b) const{return x * b.x + y * b.y;}//点积 db operator ^ (const Point b) const{return x * b.y - y * b.x;}//叉积,顺时针为负 booloperator == (const Point &k1) const{return db_cmp(x,k1.x)==0&&db_cmp(y,k1.y)==0;} Point & operator += (const Point &k1) {x+=k1.x;y+=k1.y;return *this;} Point & operator -= (const Point &k1) {x-=k1.x;y-=k1.y;return *this;} Point & operator *= (const db k1) {*this=*this*k1;return *this;} Point & operator /= (const db k1) {*this=*this/k1;return *this;} Point rotate(db k1){return Point(x*cos(k1)-y*sin(k1),x*sin(k1)+y*cos(k1));}// 逆时针旋转 Point rotate90(){return Point(-y,x);} db abs(){returnsqrt(x*x+y*y);} db abs2(){return x*x+y*y;} Point unit(){return *this/abs();} db angle(){returnatan2(y,x);} voidout(){printf("%.10f %.10f\n",x,y);} }; typedef Point Vector; intinmid(Point k1,Point k2,Point k3){return inmid(k1.x,k2.x,k3.x)&&inmid(k1.y,k2.y,k3.y);} db angleOfTwoVector(Vector a, Vector b){returnfabs(atan2(a ^ b, a * b));} Point proj(Point q,Point k1,Point k2){ // q 到直线 k1,k2 的投影 Point k=k2-k1; return k1+k*((q-k1)*k/k.abs2()); } Point reflect(Point q,Point k1,Point k2){// q 关于直线 k1,k2 的对称点 return proj(q,k1,k2)*2-q; } Point getLL(Point k1,Point k2,Point k3,Point k4){//直线交点 db w1=(k1-k3)^(k4-k3),w2=(k4-k3)^(k2-k3); return (k1*w2+k2*w1)/(w1+w2); } intintersect(db l1,db r1,db l2,db r2){//是否有交集 if (l1>r1) swap(l1,r1); if (l2>r2) swap(l2,r2); return db_cmp(r1,l2)!=-1&&db_cmp(r2,l1)!=-1; } intcheckSL(Point k1,Point k2,Point k3,Point k4){// 求线段 (S) k1,k2 和直线 (L) k3,k4 的交点 return sign((k3-k1)^(k4-k1))*sign((k3-k2)^(k4-k2))<=0; } intcheckSS(Point k1,Point k2,Point k3,Point k4){//两线段是否相交 return intersect(k1.x,k2.x,k3.x,k4.x)&&intersect(k1.y,k2.y,k3.y,k4.y)&&checkSL(k1,k2,k3,k4)&&checkSL(k3,k4,k1,k2); } db disPP(Point k1,Point k2){return (k2-k1).abs();} db disPP2(Point k1,Point k2){return (k2-k1).abs2();} db disPS(Point q,Point k1,Point k2){ Point k3=proj(q,k1,k2); if (inmid(k1,k2,k3)) return disPP(q,k3); return min(disPP(q,k1),disPP(q,k2)); } db disPL(Point q,Point k1,Point k2){ if(k1==k2)return disPP(q,k1); returnfabs((q - k1) ^ (k2 - k1)) / (k2-k1).abs(); } db disSS(Point k1,Point k2,Point k3,Point k4){ if (checkSS(k1,k2,k3,k4)) return0; return min(min(disPS(k1,k3,k4),disPS(k2,k3,k4)),min(disPS(k3,k1,k2),disPS(k4,k1,k2))); } db disSL(Point k1,Point k2,Point k3,Point k4){ if (checkSL(k1,k2,k3,k4)) return0; return min(disPL(k1,k3,k4),disPL(k2,k3,k4)); } intonS(Point q,Point k1,Point k2){return inmid(k1,k2,q)&&sign((k1-q)^(k2-k1))==0;}
structLine { Point s, t; Line(){} Line(Point _s,Point _t):s(_s),t(_t){} Vector dir(){return (t-s);} Vector unitDir(){return (t-s).unit();} intplace(Point k){return sign((t-s)^(t-k));} db len(){return (t-s).abs();} }; typedef Line Segment; Point proj(Point q,Line k){return proj(q,k.s,k.t);} Point reflect(Point q,Line k){return reflect(q,k.s,k.t);} Point getLL(Line k1,Line k2){return getLL(k1.s,k1.t,k2.s,k2.t);} boolparallel(Line k1,Line k2){return sign(k1.dir()^k2.dir())==0;} boolsameDir(Line k1,Line k2){return parallel(k1,k2)&&sign(k1.dir()*k2.dir())==1;} intcheckSS(Segment k1,Segment k2){return checkSS(k1.s,k1.t,k2.s,k2.t);} intcheckSL(Segment k1,Line k2){return checkSL(k1.s,k1.t,k2.s,k2.t);} db disPS(Point a, Segment b){return disPS(a,b.s,b.t);} db disPL(Point a, Line b){return disPL(a,b.s,b.t);} db disSS(Segment k1,Segment k2){return disSS(k1.s,k1.t,k2.s,k2.t);} db disSL(Segment k1,Line k2){return disSL(k1.s,k1.t,k2.s,k2.t);} intonS(Point q,Segment k){return onS(q,k.s,k.t);}
Point a[N],center; Line b[N]; db r; intmain(){ int n; db ans=0; in(n); in(r); for0(i,n)in(a[i].x),in(a[i].y); center=Point(a[0].x,a[0].y+r); for1(i,n-1)b[i]=Segment(a[i-1],a[i]); int p=1; bool isOnLine=1; while(p<=n-1){ if(isOnLine){ Vector dir=b[p].dir(); Vector ver=dir.rotate90().unit(); Line vli=Line(b[p].s+ver*r,b[p].t+ver*r); db k=disPP(center,vli.t); isOnLine=0; p++; for(int i=p;i<n;i++){ if((vli.dir()^b[i].dir())>0&&disSS(vli,b[i])<r){ db tm=disPP(center,getLL(vli,b[i]))-dir.abs()*b[i].dir().abs()*r/abs(dir^b[i].dir()); Point t_center=center+vli.dir().unit()*tm; if(db_cmp (disPS(t_center,b[i]),r)==0&&tm<k){ k=tm; isOnLine=1; p=i; } if(r-disPS(b[i].t,vli)>-eps){ db tmp=disPL(b[i].t,vli)*disPL(b[i].t,vli); db tm=sqrt(disPP2(center,b[i].t)-tmp)-sqrt(r*r-tmp); t_center=center+vli.dir().unit()*tm; if(tm<k&&db_cmp (disPS(t_center,b[i]),r)==0){ k=tm; isOnLine=0; p=i+1; } } } } center=center+dir.unit()*k; ans+=k; }else{ Point poi=b[p-1].t; db k=angleOfTwoVector(b[p].dir().rotate90(),center-poi); isOnLine=1; for(int i=p+1;i<n;i++){ Line tm=b[i]; Vector ver =tm.dir().rotate90().unit()*r; tm.s=tm.s+ver;tm.t=tm.t+ver; if(r-disPS(poi,tm)>-eps){ db ttm=disPL(poi,tm)*disPL(poi,tm); db tmp=sqrt(disPP2(poi,tm.t)-ttm)-sqrt(r*r-ttm); Point t_center=tm.t-tm.dir().unit()*tmp; db tk=angleOfTwoVector(center-poi,t_center-poi); if(tk<k&&db_cmp(disPS(t_center,b[i]),r)==0){ k=tk; isOnLine=1; p=i; } } db tmp=disPP(poi,b[i].t); if(2*r-tmp>-eps){ tmp=sqrt(r*r-tmp*tmp/4); Point mid=(poi+b[i].t)/2; mid=mid+(b[i].t-poi).rotate90().unit()*tmp; db tk=angleOfTwoVector(center-poi,mid-poi); if(tk<k&&db_cmp(disPS(mid,b[i]),r)==0){ k=tk; isOnLine=0; p=i+1; } } } ans+=k*r; center=(center-poi).rotate(2*pi-k)+poi; } } out(ans,2,1); return0; }