zoukankan      html  css  js  c++  java
  • BZOJ4077 : [Wf2014]Messenger

    二分答案,让$A$推迟出发$mid$的时间。

    对于每个相邻的时间区间,两个点都是做匀速直线运动。

    以$A$为参照物,那么$A$不动,$B$作匀速直线运动。

    若线段$B$到$A$的距离不超过$mid$,则可行。

    时间复杂度$O(nlog n)$。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int N=50010;
    const double eps=1e-9;
    inline int sgn(double x){
      if(x<-eps)return -1;
      if(x>eps)return 1;
      return 0;
    }
    int n,m,i;double l,r,mid,f[N],da[N],db[N];
    struct P{
      double x,y;
      P(){}
      P(double _x,double _y){x=_x,y=_y;}
      P operator+(const P&b){return P(x+b.x,y+b.y);}
      P operator-(const P&b){return P(x-b.x,y-b.y);}
      P operator*(double b){return P(x*b,y*b);}
      P operator/(double b){return P(x/b,y/b);}
      double operator*(const P&b){return x*b.x+y*b.y;}
      double len(){return hypot(x,y);}
      void read(){scanf("%lf%lf",&x,&y);}
    }a[N],b[N];
    inline double cross(P a,P b){return a.x*b.y-a.y*b.x;}
    inline P lerp(P a,P b,double t){return a*(1.0-t)+b*t;}
    inline double dist_point_to_segment(P p,P a,P b){
      if((b-a).len()>eps&&sgn((p-a)*(b-a))>=0&&sgn((p-b)*(a-b))>=0)return fabs(cross(p-a,b-a))/(b-a).len();
      return min((p-a).len(),(p-b).len());
    }
    inline double cal(P A,P B,P C,P D,double t){
      B=B-A;
      B=B/B.len();
      D=D-C;
      D=D/D.len();
      D=D-B;
      return dist_point_to_segment(A,C,C+D*t);
    }
    bool check(double mid){
      int i=1,j;
      P A=a[1],B;
      double v=0,w;
      for(j=1;j<m;j++)if(mid<f[j]){
        w=mid-f[j-1];
        B=lerp(b[j],b[j+1],w/db[j]);
        break;
      }
      if(j==m)return 1;
      while(i<n&&j<m){
        double x=(A-a[i+1]).len(),y=(B-b[j+1]).len();
        if((A-B).len()<mid+eps)return 1;
        if(x>eps&&y>eps)if(cal(A,a[i+1],B,b[j+1],min(x,y))<mid+eps)return 1;
        if(!sgn(x-y)){
          A=a[++i];
          B=b[++j];
          v=w=0;
          continue;
        }
        if(x<y){
          A=a[++i];
          v=0;
          w+=x;
          B=lerp(b[j],b[j+1],w/db[j]);
          continue;
        }
        v+=y;
        A=lerp(a[i],a[i+1],v/da[i]);
        B=b[++j];
        w=0;
      }
      return 0;
    }
    int main(){
      scanf("%d",&n);
      for(i=1;i<=n;i++)a[i].read();
      scanf("%d",&m);
      for(i=1;i<=m;i++)b[i].read();
      for(i=1;i<n;i++)da[i]=(a[i]-a[i+1]).len();
      for(i=1;i<m;i++)db[i]=(b[i]-b[i+1]).len();
      for(i=1;i<m;i++)f[i]=f[i-1]+db[i];
      r=f[m-1];
      if((a[1]-b[m]).len()>r+eps)return puts("impossible"),0;
      for(i=40;i;i--)if(check(mid=(l+r)/2))r=mid;else l=mid;
      return printf("%.8f",(l+r)/2),0;
    }
    

      

  • 相关阅读:
    WPF 登录窗口关闭时打开主窗口
    WPF Expander获得ToggleButton
    .NET Framework 4 与 .NET Framework 4 Client Profile
    WPF 根据枚举值名称 获得枚举值
    WPF KeyDown不响应方向键、Home/End/PgUp/PgDn等功能键
    C# MemoryStream和BinaryFormatter
    VB INET控件的全部用法
    C#写文件方法总结
    C#实现ADSL拨号(源代码例程)
    使用C#实现ADSL自动拨号(原理及封闭类)
  • 原文地址:https://www.cnblogs.com/clrs97/p/6654995.html
Copyright © 2011-2022 走看看