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\n",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\n",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\n",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\n",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\n",s1,s2);
	}
	return 0;
}
posted @ 2019-10-08 10:22  wyxdrqcccc  阅读(128)  评论(0编辑  收藏  举报