• Loj2604开车旅行


    Loj2604开车旅行

    我完全没有看出这道题哪里是DP

    首先,一个位置向后的最近和第二近我们可以通过set去简单实现
    通过维护最大和次大即可

    至于高度相同的情况我们可以通过先在set中查询小的来实现

    接下来我们考虑倍增

    (f_{i,j})表示从位置(j)开始向后开(2^i)次所到达的位置(这里一次的定义是小A走一次然后小B再走一次)

    我们设(g1_{i,j})表示从(j)开始向后走(2^i)步的过程中小A走的路程,(g2_{i,j})表示小B的

    我们每次对于一个(s_i,x_i)我们尝试在(s_i)位置倍增向后跳,跳到马上大于(x_i)或者无路可走位置

    如果无路可走,说明剩下的路程不满足走一次,但是可能出现小A还能走得情况,所以要特判

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<cmath>
    #include<algorithm>
    #define pii pair<int,int>
    #define mk make_pair
    #define fi first
    #define se second
    #define LL long long 
    using namespace std;
    const int N = 2e5 + 3;
    const int INF = 2e9;
    int n,m;
    int h[N];
    pii nxt1[N],nxt2[N];
    int f[21][N];
    LL g1[21][N],g2[21][N];
    set < pii > s;
    set < pii >::iterator it;
    inline int read(){
    	int v = 0,c = 1;char ch = getchar();
    	while(!isdigit(ch)){
    		if(ch == '-') c = -1;
    		ch = getchar();
    	}
    	while(isdigit(ch)){
    		v = v * 10 + ch - 48;
    		ch = getchar();	
    	}
    	return v * c;
    }
    int main(){
    	n = read();
    	for(int i = 1;i <= n;++i) h[i] = read();
    	for(int i = n;i >= 1;--i){
    		pii f1 = mk(INF,0),f2 = mk(INF,0);LL v = 0;
    		it = s.lower_bound(mk(h[i],i));
    		if(it != s.begin()){
    			it--;
    			v = abs((*it).fi - h[i]);
    			if(v < f1.fi) f2 = f1,f1 = mk(v,(*it).se);
    			else if(v < f2.fi) f2 = mk(v,(*it).se);
    			if(it != s.begin()){
    				it--;	
    				v = abs((*it).fi - h[i]);
    				if(v < f1.fi) f2 = f1,f1 = mk(v,(*it).se);
    				else if(v < f2.fi) f2 = mk(v,(*it).se);
    			}
    		}
    		it = s.upper_bound(mk(h[i],i));
    		if(it != s.end()){
    			v = abs((*it).fi - h[i]);
    			if(v < f1.fi) f2 = f1,f1 = mk(v,(*it).se);
    			else if(v < f2.fi) f2 = mk(v,(*it).se);
    			it++;
    			if(it != s.end()){
    				v = abs((*it).fi - h[i]);	
    				if(abs((*it).fi - h[i]) < f1.fi) f2 = f1,f1 = mk(v,(*it).se);
    				else if(v < f2.fi) f2 = mk(v,(*it).se);
    			}	
    		}
    		if(f1.se) nxt1[i] = f1;
    		if(f2.se) nxt2[i] = f2;
    		s.insert(mk(h[i],i));
    	}
    	for(int i = 1;i <= n;++i){
    	//	printf("1s:%d 1id:%d 2s:%d 2id:%d
    ",nxt1[i].fi,nxt1[i].se,nxt2[i].fi,nxt2[i].se);
    		f[0][i]	= nxt1[nxt2[i].se].se;
    		g1[0][i] = nxt2[i].fi;
    		g2[0][i] = nxt1[nxt2[i].se].fi;
    	//	printf("%d %lld %lld
    ",f[0][i],g1[0][i],g2[0][i]);
    	}
    	for(int i = 1;i < 20;++i){
    		for(int j = 1;j <= n;++j){
    			f[i][j] = f[i - 1][f[i - 1][j]];
    			if(f[i][j]){
    				g1[i][j] = g1[i - 1][j] + g1[i - 1][f[i - 1][j]];
    				g2[i][j] = g2[i - 1][j] + g2[i - 1][f[i - 1][j]];
    			}
    		}
    	}
    //	printf("%d %lld %lld
    ",f[1][1],g1[1][1],g2[1][1]);
    	LL x0 = read();int maxxhi = 0,id = 0;LL zi = 0,mu = 0;
    	for(int i = 1;i <= n;++i){
    		LL z1 = 0,m1 = 0,tt = 0;int x = i;
    		for(int j = 19;j >= 0;--j){
    			if(f[j][x]){
    				if(tt + g1[j][x] + g2[j][x] <= x0){
    					tt += g1[j][x] + g2[j][x];
    					z1 += g1[j][x],m1 += g2[j][x],x = f[j][x];	
    				}
    			}	
    		}
    		if(nxt2[x].se && tt + nxt2[x].fi <= x0) tt += nxt2[x].fi,z1 += nxt2[x].fi;
    		if(m1 == 0){
    			if(mu != 0) continue;
    			if(maxxhi < h[i]) zi = z1,mu = m1,maxxhi = h[i],id = i;	
    		}
    		else{
    			if(mu == 0){
    				zi = z1,mu = m1,maxxhi = h[i],id = i;
    				continue;
    			}
    			if(z1 * mu < zi * m1) zi = z1,mu = m1,maxxhi = h[i],id = i;
    			else if(z1 * mu == zi * m1 && maxxhi < h[i]) zi = z1,mu = m1,maxxhi = h[i],id = i;
    		}
    	}
    	printf("%d
    ",id);
    	m = read();
    	while(m--){
    		int si = read(),xi = read();
    		LL s1 = 0,s2 = 0;int x = si;LL tt = 0;
    		for(int j = 19;j >= 0;--j){
    			if(f[j][x]){
    				if(tt + g1[j][x] + g2[j][x] <= xi){
    					tt += g1[j][x] + g2[j][x];
    					s1 += g1[j][x],s2 += g2[j][x],x = f[j][x];	
    				}
    			}	
    		}
    		if(nxt2[x].se && tt + nxt2[x].fi <= xi) s1 += nxt2[x].fi;
    		printf("%lld %lld
    ",s1,s2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    80X86常用汇编指令集(不断补充完善中)
    重温大师经典:Martin Fowler 的持续集成
    .NET Framework 将有限地向开发者公开源代码
    DotNet源代码中的模式Builder生成器模式
    Delphi内嵌汇编语言BASM精要(转帖)
    sealed关键字用法
    VS2008设置查看.NET源码的方法
    基于LINQ to SQL的WEB开发三层架构(1)
    拓扑排序
    HDU1495 非常可乐(BFS)
  • 原文地址:https://www.cnblogs.com/wyxdrqc/p/11633941.html
Copyright © 2020-2023  润新知