BZOJ4081 : [Wf2014]Skiing

首先将目标点按$y$坐标从小到大排序。

如果加速度为$0$,那么只要贪心走一遍即可。

否则考虑DP,设$f[i][j]$表示从$i$点以速度$j$出发最多能经过多少个点。

注意到将DP值相同的合并可以将$f[i][j]$按$j$划分成$O(n)$段区间,故用区间进行整体转移即可。

在求出DP数组后,再从原点出发,每次贪心选取字典序最小的且能走到最多点数的后继即可。

时间复杂度$O(n^3\log n)$。

 

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=260,M=N*2;
const double inf=1e20,eps=1e-9;
int _,n,i,j,k,x,y,X,ret,cnt[N],cg;double vy,ma,l,r,vl,vr;
struct P{int x,y,p;}a[N];
struct E{
  double l,r;int f;
  E(){}
  E(double _l,double _r,int _f){l=_l,r=_r,f=_f;}
}f[N][M],g[N*M],h[N*M];
inline bool cmp(const P&a,const P&b){return a.y==b.y?a.p<b.p:a.y<b.y;}
inline bool cmpE(const E&a,const E&b){return a.l<b.l;}
void NO(){
  puts("Cannot visit any targets");
  exit(0);
}
inline int sgn(double x){
  if(x>eps)return 1;
  if(x<-eps)return -1;
  return 0;
}
inline void cal(int dy,int d,double L,double R){
  if(!dy){
    if(d){
      l=inf,r=-inf;
      return;
    }
    l=L,r=R;
    return;
  }
  double t=dy/vy;
  L=max(L,1.0*d/t-ma*t/2);
  R=min(R,1.0*d/t+ma*t/2);
  if(sgn(L-R)>=0){
    l=inf,r=-inf;
    return;
  }
  double A=ma,B=-2.0*ma*t,C=0.5*ma*t*t+L*t-d;
  double x=(-B-sqrt(max(B*B-4.0*A*C,0.0)))/(A*2.0);
  r=L-ma*x+ma*(t-x);
  A=-ma,B=2.0*ma*t,C=-0.5*ma*t*t+R*t-d;
  x=(-B+sqrt(max(B*B-4.0*A*C,0.0)))/(A*2.0);
  l=R+ma*x-ma*(t-x);
}
inline void merge(){
  static int c[N],l[N],r[N];
  int i;
  for(i=0;i<=n;i++)c[i]=0;
  for(i=1;i<=cg;i++)c[n-g[i].f]++;
  l[0]=1,r[0]=c[0];
  for(i=1;i<=n;i++)l[i]=c[i-1]+1,r[i]=c[i]+=c[i-1];
  for(i=1;i<=cg;i++)h[c[n-g[i].f]--]=g[i];
  for(i=0;i<=n;i++)if(l[i]<r[i])sort(h+l[i],h+r[i]+1,cmpE);
  int m=1;
  for(i=2;i<=cg;i++){
    if(h[i].f==h[m].f&&sgn(h[m].r-h[i].l)>=0)h[m].r=max(h[m].r,h[i].r);
    else h[++m]=h[i];
  }
  cg=m;
}
inline void go(int x){
  int Y,Z=n+1,i,j,k;
  for(i=n;i>X;i--)if(a[i].p<Z){
    bool flag=0;
    for(j=1;j<=cnt[i];j++)if(f[i][j].f==x-1)for(k=1;k<=cg;k++){
      cal(a[i].y-a[X].y,a[i].x-a[X].x,g[k].l,g[k].r);
      l=max(l,f[i][j].l);
      r=min(r,f[i][j].r);
      if(sgn(l-r)>=0)continue;
      flag=1;
      break;
    }
    if(flag)Y=i,Z=a[i].p;
  }
  printf("%d",Z);
  if(x>1)putchar(' ');
  int m=0;
  for(j=1;j<=cnt[Y];j++)if(f[Y][j].f==x-1)for(k=1;k<=cg;k++){
    cal(a[Y].y-a[X].y,a[Y].x-a[X].x,g[k].l,g[k].r);
    l=max(l,f[Y][j].l);
    r=min(r,f[Y][j].r);
    if(sgn(l-r)>=0)continue;
    h[++m]=E(l,r,0);
  }
  for(i=1;i<=m;i++)g[i]=h[i];
  cg=m;
  X=Y;
}
int main(){
  scanf("%d%lf%lf",&_,&vy,&ma);
  while(_--){
    scanf("%d%d",&x,&y);
    if(y<0)continue;
    a[++n].x=x;
    a[n].y=y;
  }
  if(!n)NO();
  for(i=1;i<=n;i++)a[i].p=i;
  sort(a,a+n+1,cmp);
  if(ma<0.5){
    for(_=0,i=1;i<=n;i++)if(a[i].x==0){
      if(_++)putchar(' ');
      printf("%d",a[i].p);
    }
    if(!_)NO();
    return 0;
  }
  for(i=n;~i;i--){
    g[cg=1]=E(-inf,inf,0);
    for(j=n;j>i;j--)for(k=1;k<=cnt[j];k++){
      cal(a[j].y-a[i].y,a[j].x-a[i].x,f[j][k].l,f[j][k].r);
      if(sgn(l-r)>=0)continue;
      g[++cg]=E(l,r,f[j][k].f+1);
    }
    merge();
    for(j=1;j<=cg;j++)f[i][j]=h[j];
    cnt[i]=cg;
  }
  for(i=1;i<=cnt[0];i++)if(f[0][i].l<eps&&f[0][i].r>-eps&&f[0][i].f){
    ret=f[0][i].f;
    break;
  }
  if(!ret)NO();
  g[cg=1]=E(-eps,eps,0);
  for(i=ret;i;i--)go(i);
  return 0;
}

  

posted @ 2017-04-07 00:31  Claris  阅读(324)  评论(0编辑  收藏  举报