zoukankan      html  css  js  c++  java
  • vijos P1780 【NOIP2012】 开车旅行

    描述

    小(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$行驶的路程总数。

    输入格式

    第一行包含一个整数$N$,表示城市的数目。 
    第二行有$N$个整数,每两个整数之间用一个空格隔开,依次表示城市$1$到城市$N$的海拔高度,即$H_1,H_2,……,H_n,$且每个$H_i$都是不同的。 
    第三行包含一个整数$X_0$。 
    第四行为一个整数$M$,表示给定$M$组$S_i$和$X_i$。 
    接下来的$M$行,每行包含$2$个整数$S_i$和$X_i$,表示从城市$S_i$出发,最多行驶$X_i$公里。

    输出格式

    输出共$M+1$行。 
    第一行包含一个整数$S_0$,表示对于给定的$X_0$,从编号为$S_0$的城市出发,小$A$开车行驶的路程总数与小$B$行驶的路程总数的比值最小。 
    接下来的$M$行,每行包含$2$个整数,之间用一个空格隔开,依次表示在给定的$S_i$和$X_i$下小$A$行驶的里程总数和小$B$行驶的里程总数。

    提示

    对于$30\%$的数据,有$1leq Nleq 20,1leq Mleq 20$; 
    对于$40\%$的数据,有$1leq Nleq 100,1leq Mleq 100$; 
    对于$50\%$的数据,有$1leq Nleq 100,1leq Mleq 1000$;
    对于$70\%$的数据,有$1leq Nleq 1000,1leq Mleq 10000$;
    对于$100\%$的数据,有$1leq Nleq 10^5,1leq Mleq 10^4,-10^9leq Hleq 10^9,0leq X_0leq 10^9,1leq S_ileq N,0leq Xileq 10^9$,数据保证$H_i$互不相同。

      这道题是很久以前刷$noip$题的时候留下来未解决的,现在来填个坑……

      一开始我写的是平衡树,现在看了$NOI$年鉴之后才意识到可以使用排序加链表来解决……

      我们先考虑如果我们知道了每个位置往后最近的城市和次近的城市,那么我们可以使用倍增来解决这道题。我们处理出每个位置往后跳$2^i$所在的位置以及此时小$A$走过的距离和小$B$走过的距离,第二问的每个询问就可以在$O(log n)$的复杂度内得到解决。而第一位又可以枚举起点算一算,所以,我们主要是要找出每个点往后会走到哪儿。

      当然,我们可以考虑从后往前扫一遍,那么我们需要支持的操作有两个:加入一个值,以及查询比某个值大的最小、次小值,比这个值小的最大、次大值。这样的话我们就需要一颗平衡树。虽然直接调用$set$即可解决,但是常数非常之大,我之前就在$vijos$上被卡$TLE$了一个点,并且死活过不去。

      我们现在来考虑一种新的方法。其实这种方法在今年$noip$的初赛中就已经出现了。我们可以把所有的高度排好序,并且记录下原位置。然后,我们按照排序之后的顺序构建一个双向链表,按原顺序扫一遍。在这个双向链表中我们可以非常轻易地找出我们所需要的信息,并且每次用完这个点之后我们需要将它删除,在这个双向链表中也可以在常数复杂度内做到。所以,我们就没有必要使用平衡树了。

      下面贴代码(代码有点丑):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    #define maxn 100010
    #define INF (1LL<<60)
    
    using namespace std;
    typedef long long llg;
    
    struct data{
    	llg x;int y;
    	data(llg a=0,int b=0):x(a),y(b){}
    }a[5];
    int wh[maxn],n,m,pr[maxn],ne[maxn],ns;
    int X,to[maxn][17],na[maxn],nb[maxn],fa[maxn],fb[maxn];
    llg ca,cb,va[maxn][17],vb[maxn][17],h[maxn];
    double now;
    
    int getint(){
    	int w=0;bool q=0;
    	char c=getchar();
    	while((c>'9'||c<'0')&&c!='-') c=getchar();
    	if(c=='-') c=getchar(),q=1;
    	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
    	return q?-w:w;
    }
    
    bool operator < (data x,data y){
    	if(x.x!=y.x) return x.x<y.x;
    	return h[x.y]<h[y.y];
    }
    
    void qsort(int l,int r){
    	int i=l,j=r,mid=h[wh[(l+r)>>1]];
    	while(i<=j){
    		while(h[wh[i]]<mid) i++;
    		while(h[wh[j]]>mid) j--;
    		if(i<=j) swap(wh[i++],wh[j--]);
    	}
    	if(i<r) qsort(i,r);
    	if(j>l) qsort(l,j);
    }
    
    void pre(){
    	wh[n+1]=ne[n+1]=n+1; h[0]=-INF; h[n+1]=INF;
    	for(int i=1;i<=n;i++) ne[wh[i]]=wh[i+1],pr[wh[i]]=wh[i-1];
    	for(int i=1;i<=n;i++){
    		a[1]=data(h[ne[i]]-h[i],ne[i]); a[2]=data(h[ne[ne[i]]]-h[i],ne[ne[i]]);
    		a[3]=data(h[i]-h[pr[i]],pr[i]); a[4]=data(h[i]-h[pr[pr[i]]],pr[pr[i]]);
    		if(pr[i]>=1) ne[pr[i]]=ne[i]; if(ne[i]<=n) pr[ne[i]]=pr[i];
    		sort(a+1,a+5); nb[i]=a[1].y%(n+1); na[i]=a[2].y%(n+1);
    		fa[i]=a[2].x; fb[i]=a[1].x;
    	}
    	for(int i=1;i<=n;i++){
    		if(na[i]) va[i][0]=fa[i],to[i][0]=na[i];
    		if(nb[na[i]]) va[i][1]=va[i][0],vb[i][1]=fb[na[i]],to[i][1]=nb[na[i]];
    	}
    	for(int j=2;j<=16;j++){
    		for(int i=1;i<=n;i++){
    			if(to[to[i][j-1]][j-1]){
    				va[i][j]=va[i][j-1]+va[to[i][j-1]][j-1];
    				vb[i][j]=vb[i][j-1]+vb[to[i][j-1]][j-1];
    				to[i][j]=to[to[i][j-1]][j-1];
    			}
    		}
    	}
    }
    
    double cal(){
    	if(!cb) return (1LL<<60);
    	return (double)ca/(double)cb;
    }
    
    void solve(int S,int X){
    	ca=cb=0;
    	for(int i=16;i>=0;i--)
    		if(to[S][i] && ca+cb+va[S][i]+vb[S][i]<=X)
    			ca+=va[S][i],cb+=vb[S][i],S=to[S][i];
    }
    
    int main(){
    	File("a");
    	n=getint();
    	for(int i=1;i<=n;i++) h[i]=getint(),wh[i]=i;
    	qsort(1,n); pre(); now=1e100; X=getint();
    	for(int i=1;i<=n;i++){
    		solve(wh[i],X); double x=cal();
    		if(x<=now) now=x,ns=wh[i];
    	}
    	printf("%d
    ",ns);
    	m=getint();
    	while(m--){
    		int s=getint(),x=getint(); solve(s,x);
    		printf("%lld %lld
    ",ca,cb);
    	}
    	return 0;
    }

      几个提交的地方:vijos P1780codevs 1199

  • 相关阅读:
    浅谈如何学好前后端
    MONGDB的使用
    一个css3特效
    axios
    css实现响应式图片及各种效果
    jQuery中.bind() .live() .delegate() .on()的区别
    HTML5 Web 存储
    HTML5中新的语义元素
    html5shiv:用于解决IE9以下版本浏览器对HTML5新增标签不识别,并导致CSS不起作用的问题
    JS移动客户端--触屏滑动事件
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/6067316.html
Copyright © 2011-2022 走看看