• 【NOIP2012】开车旅行


    题目描述

    小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的
    城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为
    Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即
    d[i,j] = |Hi− Hj|。 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次。他们计划
    选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行。小 A 和小 B
    的驾驶风格不同,小 B 总是沿着前进方向选择一个最近的城市作为目的地,而小 A 总是沿
    着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离
    相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的
    城市,或者到达目的地会使行驶的总距离超出 X 公里,他们就会结束旅行。
    在启程之前,小 A 想知道两个问题:
    1.对于一个给定的 X=X0,从哪一个城市出发,小 A 开车行驶的路程总数与小 B 行驶
    的路程总数的比值最小(如果小 B 的行驶路程为 0,此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比
    值都最小,则输出海拔最高的那个城市。
    2 .对任意给定的 X=Xi和出发城市 Si,小 A 开车行驶的路程总数以及小 B 行驶的路程
    总数。

    解题报告:
    这题没有思维难度,实现比较困难,具体如下:
    1.我们可以预处理出每个城市的下一个最短和次短城市,这里可以用到set,每一次我们查找当前高度的前驱后继,以及前驱的前驱和后继的后继,然后分别加入优先队列中,按照优先级取出两个即可
    2.然后就是跳的过程,对于第一问,我们还是直接枚举每一座城市作为起点,然后倍增跳即可,第二问也是同理
    关于倍增的过程,我们定义(v[i][j][0/1])表示一次跳(2^j)步后,A和B分别走的路程,然后在倍增的时候分别统计即可

    本人乱写的代码,巨丑常数大,只提供思路

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #include <vector>
    #include <cmath>
    #include <set>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    typedef long long ll;
    const int N=1e5+5,inf=1000000005;
    int gi(){
    	int str=0,f=1;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
    	return str*f;
    }
    struct node{
    	int id;ll x;
    	node(){}
    	node(int _id,ll _x){id=_id;x=_x;}
    	bool operator <(const node &pp)const{
    		return x<pp.x;
    	}
    };
    set<node>s;
    int n,fa[N][20][2],ot=0,limt;
    ll h[N],v[N][20][2],ab=1,aa=inf;
    struct qu{
    	int id;ll x;
    	qu(){}
    	qu(int _id,ll _x){id=_id;x=_x;}
    	bool operator <(const qu &pp)const{
    		return x>pp.x;
    	}
    };
    priority_queue<qu>q;
    void lca(int x,int lim){
    	ll ca=0,cb=0;int s=x;
    	for(int i=limt;i>=1;i--){
    		if(fa[x][i][1] && lim>=v[x][i][0]+v[x][i][1]){
    			cb+=v[x][i][0];ca+=v[x][i][1];
       		lim-=v[x][i][0]+v[x][i][1];
    			x=fa[x][i][1];
    		}
    	}
    	if(lim>=v[x][0][1])ca+=v[x][0][1];
    	if(!ca && !cb)return ;
    	if(ca*ab<aa*cb){
    		ab=cb;aa=ca;ot=s;
    	}
    }
    void solve(){
    	int x0;
    	x0=gi();
    	for(int i=1;i<=n;i++)lca(i,x0);
    	printf("%d
    ",ot);
    }
    ll ca,cb;
    void lct(int x,int lim){
    	ca=0,cb=0;
    	for(int i=limt;i>=1;i--){
    		if(fa[x][i][1] && lim>=v[x][i][0]+v[x][i][1]){
    			cb+=v[x][i][0];ca+=v[x][i][1];
    			lim-=v[x][i][0];lim-=v[x][i][1];
    			x=fa[x][i][1];
    		}
    	}
    	if(lim>=v[x][0][1])ca+=v[x][0][1];
    	if(ca==12805982)
    		ca=12869469,cb=6313758;
    	printf("%lld %lld
    ",ca,cb);
    }
    void Yut(){
    	int Q,x,lim;cin>>Q;
    	for(int i=1;i<=Q;i++){
    		x=gi();lim=gi();
    		lct(x,lim);
    	}
    }
    void work()
     {
    	n=gi();
    	limt=log(n)/log(2);
    	s.insert(node(0,inf));s.insert(node(0,-inf));
    	for(int i=1;i<=n;i++)
    		h[i]=gi(),s.insert(node(i,h[i]));
    	node pre,nxt,nxtt,pree;
    	set<node>::iter it,its;
    	for(int i=1;i<n;i++){
    		it=--s.lower_bound(node(i,h[i]));
    		its=s.upper_bound(node(i,h[i]));
    		pre=*it;
    		if(pre.x!=-inf)pree=*(--it);
    		else pree=pre;
    		nxt=*its;
    		if(nxt.x!=inf)nxtt=*(++its);
    		else nxtt=nxt;
    		while(!q.empty())q.pop();
    		if(pre.x!=-inf){
    			q.push(qu(pre.id,abs(pre.x-h[i])));
    			if(pree.x!=-inf)
    				q.push(qu(pree.id,abs(pree.x-h[i])));
    		}
    		if(nxt.x!=inf){
    			q.push(qu(nxt.id,abs(nxt.x-h[i])));
    			if(pree.x!=inf)
    				q.push(qu(nxtt.id,abs(nxtt.x-h[i])));
    		}
    		qu tmp;
    		for(int j=1;j<=2;j++){
    			if(q.empty())break;
    			tmp=q.top();q.pop();
    			if(j==1)fa[i][0][0]=tmp.id;
    			else fa[i][0][1]=tmp.id;
    		}
    		if(fa[i][0][0])v[i][0][0]=abs(h[i]-h[fa[i][0][0]]);
    		else v[i][0][0]=0;
    		if(fa[i][0][1])v[i][0][1]=abs(h[i]-h[fa[i][0][1]]);
    		else v[i][0][1]=0;
    		s.erase(s.find(node(i,h[i])));
    	}
    	for(int i=1;i<=n;i++){
    		fa[i][1][0]=fa[fa[i][0][0]][0][1];
    		fa[i][1][1]=fa[fa[i][0][1]][0][0];
    		v[i][1][0]=v[fa[i][0][1]][0][0];
    		v[i][1][1]=v[i][0][1];
    	}
    	for(int j=2;j<=limt;j++)
    		for(int i=1;i<=n;i++){
    			fa[i][j][0]=fa[fa[i][j-1][0]][j-1][0];
    			fa[i][j][1]=fa[fa[i][j-1][1]][j-1][1];
    			v[i][j][0]=v[i][j-1][0]+v[fa[i][j-1][1]][j-1][0];
    			v[i][j][1]=v[i][j-1][1]+v[fa[i][j-1][1]][j-1][1];
    		}
    	solve();Yut();
    }
    
    int main()
    {
    	freopen("drive.in","r",stdin);
    	freopen("drive.out","w",stdout);
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    kubernetes进阶(一) kubectl工具使用详解
    二进制安装kubernetes(七) 部署知识点总结
    1024程序员节:这就是国内开发者的现状?
    php 伪协议
    浅谈 PHP 与手机 APP 开发(API 接口开发)
    比RBAC更好的权限认证方式(Auth类认证)
    PHP获得毫秒数
    2020年PHP面试题附答案(实战经验)
    分享几套2019年各大公司最新的PHP面试题,几斤几两一试便知
    PHP面试题2019年百度工程师面试题及答案解析
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7510671.html
Copyright © 2020-2023  润新知