對於這題,我無力吐槽。ios
雖然式子仍是不難想,作法也隨便口胡,可是一些鬼畜邊界狀況就是判不對。c++
首先顯然二分答案。ide
對於每個雨滴,它出現的時刻咱們的繩子必須落在它上面。把繩子的上下端點用二元組\((a,b)\)表示,由於三個點\((a,0)(x_i,y_i)(b,h)\)共線,咱們能夠推出
\[(b-a,h)×(x_i-a,y_i)=0\\(h-y_i)a+y_ib-x_ih=0\]
這說明了\(a,b\)的關係,必須落在一條直線上!它在\((0,0)(0,w)(w,w)(w,0)\)矩形範圍內的部分就是可行域。this
如今,咱們初始的可行域是一個點\((e1,e2)\),到下一個時刻以前,可行域會向四周擴散\(v*\Delta t\)個單位,造成了一個正方形。這個正方形與下一個可行域線段的交,就是當前真正的可行域。那假如當前可行域是一個線段,它擴散是什麼樣子呢?是一個六邊形,等於線段和正方形的閔可夫斯基和。spa
一個線段和一個凸包的交怎麼求呢?個人作法比較蒟蒻,把線段和凸包的交點求出來,按交點個數、端點與凸包的位置關係分類討論一下。code
咱們不斷地作下去,中途若是出現可行域沒有交了就說明不合法。htm
接下來是實現細節。blog
首先,對於\(t\)相同的雨滴,咱們直接把它們的可行域合併,以避免接下來作閔可夫斯基和的時候凸包退化成點或線段。ip
頭疼的就是這裏了。合併的時候,要分紅線段和線段的交,線段和點的交,點和點的交討論個半天。由於線段和線段能夠直接套SegCross
求交點,可是線段和點不能套,會除\(0\)。注意線段平行/重合還要單獨拿出來判,不過顯然若是重合的話\(x,y\)都是相等的,否則就平行也就是沒有交集了,直接cout<<"-1"
。
再就是特判的時候有些地方非得用EPS,否則過不了。由於值域爲整數並且範圍只有\(10^3\),因此EPS設大點不要緊,小於\(\frac{1}{\text{值域}^2}\)就能夠了。
慘痛的教訓:強烈建議不要試圖將此題做爲計算幾何板子的練習題,由於光是討論就不知道比敲板子麻煩到哪裏去了。有些醜陋的板子看不懂的話就去踩蒟蒻的總結吧。
#include<bits/stdc++.h> #define R register int #define I inline #define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin)) using namespace std; typedef double DB; const int SZ=1<<19,N=1e5+9; const DB EPS=1e-8; char buf[SZ],*ie=buf+SZ,*ip=ie-1; inline int in(){ G;while(*ip<'-')G; R x=*ip&15;G; while(*ip>'-'){x*=10;x+=*ip&15;G;} return x; } inline bool is0(DB x){return fabs(x)<EPS;} struct Vec{ DB x,y; I Vec(){x=y=0;} I Vec(DB a){x=a;y=0;} I Vec(DB a,DB b){x=a;y=b;} I friend istream&operator>>(istream&cin,Vec&a){return a.x=in(),a.y=in(),cin;} I Vec operator-(){return Vec(-x,-y);} I Vec operator+(Vec a){return Vec(x+a.x,y+a.y);} I Vec operator-(Vec a){return Vec(x-a.x,y-a.y);} I Vec operator*(DB a){return Vec(x*a,y*a);} I Vec operator/(DB a){return Vec(x/a,y/a);} I friend Vec operator*(DB a,Vec b){b.x*=a,b.y*=a;return b;} I Vec&operator+=(Vec a){x+=a.x,y+=a.y;return*this;} I Vec&operator-=(Vec a){x-=a.x,y-=a.y;return*this;} I DB operator*(Vec a){return x*a.x+y*a.y;} I DB operator^(Vec a){return x*a.y-y*a.x;} I bool operator==(Vec a){return is0(x-a.x)&&is0(y-a.y);} I friend bool operator<(Vec a,Vec b){ return (a^b)>0||(is0(a^b)&&Len(a)<Len(b)); } I friend DB Len(Vec a){ return sqrt(a.x*a.x+a.y*a.y); } }a[N],b[N],c[9],d[9],e; int t[N],st[N]; I Vec LineCross(Vec a1,Vec a2,Vec b1,Vec b2){ a2-=a1;b2-=b1; return b2^a2?a1+(b2^(b1-a1))/(b2^a2)*a2:Vec(NAN,NAN); } I Vec SegCross(Vec&a1,Vec&a2,Vec&b1,Vec&b2){ Vec c=LineCross(a1,a2,b1,b2); return (a1-c)*(a2-c)>EPS||(b1-c)*(b2-c)>EPS?Vec(NAN,NAN):c; } I int Convex(Vec*a,R n){ R k=0,p=0;Vec bs; for(R i=1;i<n;++i) if(a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x))k=i; swap(a[0],a[k]);bs=a[0]; for(R i=0;i<n;++i)a[i]-=bs; sort(a+1,a+n); for(R i=1;i<n;st[++p]=i++) while(p&&((a[i]-a[st[p-1]])^(a[st[p]]-a[st[p-1]]))>-EPS)--p; for(R i=0;i<=p;++i)a[i]=a[st[i]]+bs; return a[p+1]=bs,p+1; } I int Minkowski(Vec*a,R n,DB t){ for(R i=n-1,j=4*n;j;--i){ a[--j]=a[i]+Vec(-t,-t); a[--j]=a[i]+Vec( t,-t); a[--j]=a[i]+Vec( t, t); a[--j]=a[i]+Vec(-t, t); } return Convex(a,4*n); } I bool Inside(Vec*a,R n,Vec v){//點是否在凸包內 for(R i=0;i<n;++i) if(((a[i+1]-a[i])^(v-a[i]))<-EPS)return 0; return 1; } I bool Check(R q,DB mid){ R n=1,p; c[0]=e; for(R i=1;i<=q;++i){ n=Minkowski(c,n,(t[i]-t[i-1])*mid); for(R j=p=0;j<n;++j){//搞出全部交點,注意去重 d[p]=SegCross(a[i],b[i],c[j],c[j+1]); p+=!(isnan(d[p].x)||(p&&d[p-1]==d[p])); } if(p==0){//更新當前可行域,討論開始 if(!Inside(c,n,a[i]))return 0; c[0]=a[i],c[1]=b[i]; } else if(p==1){ if(Inside(c,n,a[i])) c[1]=Inside(c,n,b[i])?(d[0]==b[i]?a[i]:b[i]):a[i]; else c[1]=Inside(c,n,b[i])?b[i]:d[0]; c[0]=d[0]; } else c[0]=d[0],c[1]=d[1];//討論結束 n=1+!(c[0]==c[1]); } return 1; } I void Err(bool f){if(f)cout<<"-1\n",exit(0);} int main(){ ios::sync_with_stdio(0); R n=in(),q=0,w=in(),h=in(),lx=0,ly=0; cin>>e; for(R i=1;i<=n;++i){ R tt=in(),x=in(),y=in(); Vec u=0,v=0;//求可行域線段,討論開始 if((u.x=(DB)x*h/(h-y))>w)u=Vec(w,(DB)(x*h-(h-y)*w)/y); if((v.y=(DB)x*h/y )>w)v=Vec((DB)(x*h-y*w)/(h-y),w);//討論結束 if(tt!=t[q])++q,a[q]=u,b[q]=v;//合併t相同的可行域,討論開始 else if(a[q]==b[q]){ if(u==v)Err(!(u==a[q]));//點交點 else Err(!is0((u-a[q])^(v-a[q])));//點交線段 } else if(x!=lx||y!=ly){ if(u==v)Err(!is0((u-a[q])^(u-b[q])));//點交線段 else Err(isnan((u=SegCross(a[q],b[q],u,v)).x));//線段交線段 a[q]=b[q]=u; }//討論結束 t[q]=tt;lx=x;ly=y; } DB l=0,r=w,mid; while((r-l)/max(1.0,l)>1e-4) mid=(l+r)/2,(Check(q,mid)?r:l)=mid; cout<<fixed<<setprecision(6)<<(l+r)/2<<'\n'; return 0; }