zoukankan      html  css  js  c++  java
  • [vijos1780][NOIP2012]开车旅行

    Description

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

    HINT

    \(1≤N≤10^5,1≤M≤10^4,-10^9≤H_i≤10^9,0≤X_0≤10^9,1≤S_i≤N,0≤X_i≤10^9\),保证\(H_i\)互不相同.

    Solution

    预处理出从每个城市出发距离第一小和第二小的城市.
    \(f[i][j]\)表示从\(i\)出发,走\(2^j\)轮到达的城市.
    \(g1[i][j]\)表示从\(i\)出发,走\(2^j\)轮小A走的路程.
    \(g2[i][j]\)表示从\(i\)出发,走\(2^j\)轮小B走的路程.
    倍增求解即可.

    #define K 18
    #define N 100005
    #define INF 1000000005
    typedef long long ll;
    struct city{
    	int h,x;
    }h[N];
    int f[N][K],g1[N][K],g2[N][K],nxt1[N],nxt2[N],n,m;
    set<city> s;
    set<city>::iterator xx;
    bool operator < (city x,city y){
    	if(x.h!=y.h) return x.h<y.h;
    	return x.x<y.x;
    }
    //x比y优 
    inline bool cmp(int u,int x,int y){
    	if(!x) return false;
    	if(!y) return true;
    	if(abs(h[x].h-h[u].h)!=abs(h[y].h-h[u].h))
    		return abs(h[x].h-h[u].h)<abs(h[y].h-h[u].h);
    	return h[x].h<h[y].h;
    }
    inline int dis(int x,int y){
    	if(x&&y) 
    		return abs(h[x].h-h[y].h)<INF?abs(h[x].h-h[y].h):INF;
    	return INF;
    }
    inline void drive(int u,int x,int &d1,int &d2){
    	int i;d1=d2=0;
    	while(x){
    		for(i=K-1;i>=0&&g1[u][i]+g2[u][i]>x;--i);
    		if(i<0) return;
    		x-=(g1[u][i]+g2[u][i]);
    		d1+=g1[u][i];d2+=g2[u][i];
    		u=f[u][i];
    	}
    }
    inline bool cmp2(int j,int k,int d1,int d2,int i,int id){
    	if(d1<0) return true;
    	if(d2&&k) return 1ll*j*d2<1ll*d1*k||(1ll*j*d2==1ll*d1*k&&h[i].h>h[id].h);
    	if(d2||k) return k;
    	return h[i].h>h[id].h;
    }
    inline void Aireen(){
    	n=read();
    	for(int i=1;i<=n;++i)
    		h[i].h=-read(),h[i].x=i;
    	city c1,c2;
    	s.clear();
    	for(int i=n-1;i;--i){
    		s.insert(h[i+1]);
    		c1=(*s.upper_bound(h[i]));
    		if(s.count(c1)){
    			s.erase(c1);
    			c2=(*s.upper_bound(h[i]));
    			s.insert(c1);
    			nxt1[i]=c1.x;nxt2[i]=c2.x;
    		}
    		else continue;
    	}
    	
    	s.clear();
    	for(int i=1;i<=n;++i)
    		h[i].h=-h[i].h;
    	for(int i=n-1;i;--i){
    		s.insert(h[i+1]);
    		c1=(*s.upper_bound(h[i]));
    		
    		if(s.count(c1)){
    			s.erase(c1);
    			c2=(*s.upper_bound(h[i]));
    			s.insert(c1);
    			if(cmp(i,c1.x,nxt1[i])){
    				nxt2[i]=nxt1[i];
    				nxt1[i]=c1.x;
    				if(s.count(c2)&&cmp(i,c2.x,nxt2[i]))
    					nxt2[i]=c2.x; 
    			}
    			else if(cmp(i,c1.x,nxt2[i]))
    				nxt2[i]=c1.x; 
    		}
    		else continue;
    	}
    	 
    	for(int j=0;j<K;++j)
    		g1[n][j]=g2[n][j]=g1[0][j]=g2[0][j]=INF; 
    	for(int i=n-1;i;--i){
    		f[i][0]=nxt2[i];
    		f[i][1]=nxt1[nxt2[i]];
    		g1[i][0]=g1[i][1]=dis(i,nxt2[i]);
    		g2[i][1]=dis(nxt2[i],nxt1[nxt2[i]]);
    		for(int j=2;j<K;++j){
    			f[i][j]=f[f[i][j-1]][j-1];
    			g1[i][j]=g1[i][j-1]+g1[f[i][j-1]][j-1];
    			if(g1[i][j]>INF) g1[i][j]=INF;
    			g2[i][j]=g2[i][j-1]+g2[f[i][j-1]][j-1];
    			if(g2[i][j]>INF) g2[i][j]=INF;
    		}
    	}
    	
    	int u,x,d1=-1,d2,id;
    	x=read();
    	for(int i=1,j,k;i<=n;++i){
    		drive(i,x,j,k);
    		if(cmp2(j,k,d1,d2,i,id)) d1=j,d2=k,id=i;
    	}
    	printf("%d\n",id);
    	
    	m=read();
    	while(m--){
    		u=read();x=read();
    		drive(u,x,d1,d2);
    		printf("%d %d\n",d1,d2);
    	}
    }
    

    2017-10-27 13:30:24

  • 相关阅读:
    python简单应用!用爬虫来采集天猫所有优惠券信息,写入本地文件
    python有哪些好玩的应用实现,用python爬虫做一个二维码生成器
    Python学习,给自己的代码做个合集,定制自己的桌面软件!
    用python抓取“3d”彩票数据,怎么分析你说了算!
    怎么让你的代码更Pythonic?光有技巧可不行,你还需要看这些
    Python学习汇总,做数据采集的一些小技巧,干货满满
    Python学习,还在用正则或者bs4做爬虫吗?来试试css选择器吧
    C# Windows API判断当前窗口是否与其他窗口有重叠(USER32.dll、dwmapi.dll)
    asp.net mvc 设置文本框的宽高
    C++ 判断当前系统x64 or x86
  • 原文地址:https://www.cnblogs.com/AireenYe/p/15600163.html
Copyright © 2011-2022 走看看