UVA - 11627 - Slalom(二分法)

思路很明显,对于一个确定的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
*/


你可能感兴趣的:(UVA - 11627 - Slalom(二分法))