思路很明显,对于一个确定的v 从第一个线段出发,最多能到达的区间为
(l-((y[i+1]-y[i])*hv*1.0)/v , r+((y[i+1]-y[i])*hv*1.0)/v) 然后与下一个线段相交即可。
那么二分上线就可以了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <list> #include <cmath> #include <sstream> #include <cctype> #include <string> using namespace std; typedef long long LL; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn = 1e6+100; int s[maxn],w,hv,n; double x[maxn],y[maxn]; void intersection(double& x,double& y,double a,double b){ if(y<a||b<x){x=-1;y=-1;} else if(x<=a&&b<=y) {x=a,y=b;} else if(a<=x&&y<=b) {x=x,y=y;} else if(x<=a&&a<=y){x=a;} else {y=b;} } int judge(int v){ double l=x[1],r=x[1]+w; for(int i=1;i<n;i++){ double pl = l-((y[i+1]-y[i])*hv*1.0)/v; double pr = r+((y[i+1]-y[i])*hv*1.0)/v; double tl = x[i+1],tr = x[i+1]+w; intersection(tl,tr,pl,pr); if(tl==-1) return 0; l=tl,r=tr; } return 1; } int find_max(){ int l=1,r=1e6+1; while(l<r){ int m=(l+r)>>1; if(judge(m)) l=m+1; else r = m; } if(l==1 && !judge(l)) return 0; return l-1; } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d %d %d",&w,&hv,&n); for(int i=1;i<=n;i++){ scanf("%lf %lf",&x[i],&y[i]); } int M; scanf("%d",&M); for(int i=0;i<M;i++) scanf("%d",&s[i]); sort(s,s+M); int ok = 0; int max_ = find_max(); for(int i=M-1;i>=0;i--) if(s[i]<=max_){ok=1; printf("%d\n",s[i]); break;} if(!ok) printf("IMPOSSIBLE\n"); } } /* 2 3 2 3 1 1 5 2 1 3 3 3 2 1 3 2 3 1 1 5 2 1 3 1 */