zoukankan      html  css  js  c++  java
  • Fence Obstacle Course 题解

    Fence Obstacle Course

    题目描述

    ​ 给定 (n) ((le 10^5))个平台,第 (i) 个平台高度为 (i),左右两端点为 (L_i),(R_i) ((-10^5le L_i le R_i le 10^5))

    ​ 你现在站在第 (n) 个平台上,你的横坐标为 (S) ((L_nle S le R_n)),求一个移动方案(从一个平台的左右端点往下跳)使得你到达位置 ((0,0)) ((y=0) 是一个无限长的平台)并且满足水平移动距离最小,输出这个最小水平移动距离。

    题解

    O(n^2) 暴力

    (f[i][0/1]) 表示从 (S) 到第 (i) 块平台的左(0)/右(1)端点的最小值。

    如果枚举第 (i) 块平台会从哪块平台跳下来的话复杂度过高,还要枚举横坐标并且很麻烦。

    考虑第 (i) 块平台的左右端点会跳到那个平台,只需要枚举下面的平台 (j)

    遇到第一个满足 (L_jle L_i le R_j) 的平台 (j) 时就停下来,(j) 就是从平台 (i) 的左端点跳到的平台,右端点同理。

    L[0]=R[0]=0;
    for(int i=n;i>=1;i--){
    	for(int j=i-1;j>=0;j--)
    	if(L[j]<=L[i]&&L[i]<=R[j]){
    		f[j][0]=min(f[j][0],f[i][0]+abs(L[i]-L[j]));
    		f[j][1]=min(f[j][1],f[i][0]+abs(R[j]-L[i]));
    		break;
    	}
    	for(int j=i-1;j>=0;j--)
    	if(L[j]<=R[i]&&R[i]<=R[j]){
    		f[j][0]=min(f[j][0],f[i][1]+abs(R[i]-L[j]));
    		f[j][1]=min(f[j][1],f[i][1]+abs(R[i]-R[j]));
    		break;
    	}
    }
    cout<<f[0][0]<<'
    ';
    

    满分做法

    上一个做法的瓶颈在于寻找 (j) ,可以通过线段树区间赋值,单点查询操作优化。

    具体地,从小到大枚举平台,记录左右端点下面最靠上的平台(线段树中查找),将线段树中 (L_i) ~ (R_i) 赋值为 (i)

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int delta=100010;//把负坐标偏移成正的
    int n,S,L[50010],R[50010],Lto[50010],Rto[50010];
    LL f[50010][2];
    struct SegmentTree
    {int color,l,r;}st[900000];
    inline int read()
    {
    	int x=0;bool w=0;char ch=0;
    	while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return w?-x:x;
    }
    void build(int p,int l,int r)
    {
    	st[p].l=l;st[p].r=r;st[p].color=0;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	build(p<<1,l,mid);
    	build(p<<1|1,mid+1,r);
    }
    void spread(int p)
    {
    	if(!st[p].color)return;
    	st[p<<1].color=st[p<<1|1].color=st[p].color;
    	st[p].color=0;
    }
    int ask(int p,int pos)
    {
    	if(st[p].l==st[p].r)return st[p].color;
    	spread(p);
    	int mid=(st[p].l+st[p].r)>>1;
    	if(pos<=mid)return ask(p<<1,pos);
    	return ask(p<<1|1,pos);
    }
    void change(int p,int l,int r,int c)
    {
    	if(l<=st[p].l&&st[p].r<=r)return void(st[p].color=c);
    	spread(p);
    	int mid=(st[p].l+st[p].r)>>1;
    	if(l<=mid)change(p<<1,l,r,c);
    	if(mid<r)change(p<<1|1,l,r,c);
    }
    int main()
    {
    	n=read();S=read()+delta;
    	L[0]=R[0]=delta;
    	for(int i=1;i<=n;i++){
    		L[i]=read()+delta;
    		R[i]=read()+delta;
    	}
    	build(1,1,200030);
    	for(int i=1;i<=n;i++){
    		Lto[i]=ask(1,L[i]);
    		Rto[i]=ask(1,R[i]);
    		change(1,L[i],R[i],i);
    	}
    	memset(f,0x3f,sizeof f);
    	f[n][0]=S-L[n];
    	f[n][1]=R[n]-S;
    	for(int i=n;i>=1;i--){
    		f[Lto[i]][0]=min(f[Lto[i]][0],f[i][0]+abs(L[i]-L[Lto[i]]));
    		f[Lto[i]][1]=min(f[Lto[i]][1],f[i][0]+abs(R[Lto[i]]-L[i]));
    		f[Rto[i]][0]=min(f[Rto[i]][0],f[i][1]+abs(R[i]-L[Rto[i]]));
    		f[Rto[i]][1]=min(f[Rto[i]][1],f[i][1]+abs(R[i]-R[Rto[i]]));
    	}
    	cout<<f[0][0]<<'
    ';
    }
    
  • 相关阅读:
    游戏架构草稿(1)
    蔡学镛:架构师最重视的文档
    常见拉丁字母
    图像识别学习1
    .net framework 2.0,3.0与3.5之间的关系 [转载]
    ASP.NET Session丢失问题原因及解决方案[转载]
    PLSQL 循环游标 cursor loop fetch into【转载】
    oracle case when的用法 【转载】
    Oracle to_char格式化函数 [转载]
    oracle表关联应用 【转载】
  • 原文地址:https://www.cnblogs.com/zYzYzYzYz/p/14347277.html
Copyright © 2011-2022 走看看