Luogu1081 开车旅行

代码巨长的倍增题...

显然这是没有什么决策的,选择方案都是固定的

这可以考虑倍增跳,每个位置上跳到的位置是可以通过查前驱后继解决的

有两种方式:

  一种是平衡树搞法,倒着做查完了插入

  另一种是先排序建一个链表,查完了删除

都是可以通过加哨兵节点来搞的,
结果我只想到了 set 乱搞,就写了很长

预处理完就可做了

第一问对于每个点倍增一遍,其实就是照题意模拟,倍增优化一下

第二问还是照题意模拟,倍增优化一下

暴力有 70pts ?



代码:

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <locale>
#include <cmath>
#include <set>
using namespace std;

typedef long long ll;
const int MAX_N = 100005;
const double INF = 100000000000001.0;

struct Node {
	int len, id;
	Node(int L = 0, int ID = 0) {len = L; id = ID;}
	bool operator < (const Node& b) const {
		return len < b.len;
	}
};
struct PAIR {
	ll fir, sec;
	PAIR(ll x = 0, ll y = 0) {fir = x; sec = y;}
	friend PAIR operator + (PAIR a, PAIR b) {
		return PAIR(a.fir + b.fir, a.sec + b.sec);
	}
}d[MAX_N][20][2];
int n, lg, x0, m, ans;

int h[MAX_N], f[MAX_N][20][2];
double ans_rat;
set<Node> st;

inline int rd() {
	register int x = 0, c = getchar();
	register bool f = false;
	while (!isdigit(c)) {
		f = (c == ‘-‘);
		c = getchar();
	}
	while (isdigit(c)) {
		x = x * 10 + (c ^ 48);
		c = getchar();
	}
	return f ? -x : x;
}
inline void get_for(int pos, set<Node>::iterator iter) {
	auto lef = iter, rig = iter;
	if (iter == st.begin()) {
		f[pos][0][0] = iter->id;
		d[pos][0][0].fir = abs(h[pos] - h[iter->id]);
		++iter;
		if (st.size() == 1) return;
		f[pos][0][1] = iter->id;
		d[pos][0][1].sec = abs(h[pos] - h[iter->id]);
		return;
	} else if (iter == st.end()) {
		--iter;
		f[pos][0][0] = iter->id;
		d[pos][0][0].fir = abs(h[pos] - h[iter->id]);
		if (iter == st.begin()) return;
		--iter;
		f[pos][0][1] = iter->id;
		d[pos][0][1].sec = abs(h[pos] - h[iter->id]);
		return;
	}
	++rig;
	if (rig == st.end()) {
		--lef;
		if (lef == st.begin()) {
			if (abs(h[pos] - h[lef->id]) <= abs(h[pos] - h[iter->id])) {
				f[pos][0][0] = lef->id;
				d[pos][0][0].fir = abs(h[pos] - h[lef->id]);
				f[pos][0][1] = iter->id;
				d[pos][0][1].sec = abs(h[pos] - h[iter->id]);
			} else {
				f[pos][0][0] = iter->id;
				d[pos][0][0].fir = abs(h[pos] - h[iter->id]);
				f[pos][0][1] = lef->id;
				d[pos][0][1].sec = abs(h[pos] - h[lef->id]);
			}
			return;
		}
		if (abs(h[pos] - h[lef->id]) <= abs(h[pos] - h[iter->id])) {
			f[pos][0][0] = lef->id;
			d[pos][0][0].fir = abs(h[pos] - h[lef->id]);
			--lef;
			if (abs(h[pos] - h[lef->id]) <= abs(h[pos] - h[iter->id])) {
				f[pos][0][1] = lef->id;
				d[pos][0][1].sec = abs(h[pos] - h[lef->id]);
			} else {
				f[pos][0][1] = iter->id;
				d[pos][0][1].sec = abs(h[pos] - h[iter->id]);
			}
			return;
		}
		f[pos][0][0] = iter->id;
		d[pos][0][0].fir = abs(h[pos] - h[iter->id]);
		f[pos][0][1] = lef->id;
		d[pos][0][1].sec = abs(h[pos] - h[lef->id]);
		return;
	}
	--lef;
	if (abs(h[pos] - h[lef->id]) == abs(h[pos] - h[iter->id])) {
		f[pos][0][0] = lef->id;
		d[pos][0][0].fir = abs(h[pos] - h[lef->id]);
		f[pos][0][1] = iter->id;
		d[pos][0][1].sec = abs(h[pos] - h[iter->id]);
	} else if (abs(h[pos] - h[lef->id]) < abs(h[pos] - h[iter->id])) {
		f[pos][0][0] = lef->id;
		d[pos][0][0].fir = abs(h[pos] - h[lef->id]);
		if (lef == st.begin()) {
			f[pos][0][1] = iter->id;
			d[pos][0][1].sec = abs(h[pos] - h[iter->id]);
		} else {
			--lef;
			if (abs(h[pos] - h[lef->id]) <= abs(h[pos] - h[iter->id])) {
				f[pos][0][1] = lef->id;
				d[pos][0][1].sec = abs(h[pos] - h[lef->id]);
			} else {
				f[pos][0][1] = iter->id;
				d[pos][0][1].sec = abs(h[pos] - h[iter->id]);
			}
		}
	} else {
		f[pos][0][0] = iter->id;
		d[pos][0][0].fir = abs(h[pos] - h[iter->id]);
		if (abs(h[pos] - h[lef->id]) <= abs(h[pos] - h[rig->id])) {
			f[pos][0][1] = lef->id;
			d[pos][0][1].sec = abs(h[pos] - h[lef->id]);
		} else {
			f[pos][0][1] = rig->id;
			d[pos][0][1].sec = abs(h[pos] - h[rig->id]);
		}
	}
}
inline void DBL_init() {
	for (int i = n; i >= 1; --i) {
		if (!st.empty()) {
			auto dst = st.lower_bound(h[i]);
			get_for(i, dst);
		}
		st.insert(Node(h[i], i));
	}
	for (int i = 1; i <= n && 2 + i <= n; ++i) {
		f[i][1][0] = f[f[i][0][0]][0][1];
		f[i][1][1] = f[f[i][0][1]][0][0];
		d[i][1][0] = d[i][0][0] + d[f[i][0][0]][0][1];
		d[i][1][1] = d[i][0][1] + d[f[i][0][1]][0][0];
	}
	for (int j = 2; j <= lg; ++j) {
		for (int i = 1; i <= n && (1 << j) + i <= n; ++i) {
			f[i][j][0] = f[f[i][j - 1][0]][j - 1][0];
			f[i][j][1] = f[f[i][j - 1][1]][j - 1][1];
			d[i][j][0] = d[i][j - 1][0] + d[f[i][j - 1][0]][j - 1][0];
			d[i][j][1] = d[i][j - 1][1] + d[f[i][j - 1][1]][j - 1][1];
		}
	}
}
inline void get_ans(int bgn) {
	register int pos = bgn;
	register ll dst_a = 0, dst_b = 0;
	register bool got_bgn = false;
	register double rat;
	for (int i = lg; i >= 0; --i) {
		if (!f[pos][i][1] || dst_a + dst_b + d[pos][i][1].fir + d[pos][i][1].sec > x0 || (i == 0 && !f[pos][0][0])) continue;
		got_bgn = true;
		dst_b += d[pos][i][1].fir;
		dst_a += d[pos][i][1].sec;
		pos = f[pos][i][1];
	}
	if (!got_bgn) return;
	if (dst_b == 0) {
		if (dst_a == 0) rat = 1.0;
		else rat = INF;
	} else {
		rat = double(dst_a) / double(dst_b);
	}
	if (fabs(0.0 - ans_rat) < 1e-7 || rat < ans_rat || (fabs(rat - ans_rat) < 1e-7 && h[bgn] > h[ans])) {
		ans_rat = rat;
		ans = bgn;
	}
}

int main() {
	n = rd();
	lg = int(ceil(log2(n)));
	for (int i = 1; i <= n; ++i) h[i] = rd();
	DBL_init();
	x0 = rd();
	for (int i = 1; i <= n; ++i)
		get_ans(i);
	printf("%d\n", ans);
	m = rd();
	register int s = 0, x = 0;
	register ll tot_a = 0, tot_b = 0;
	while (m--) {
		tot_a = tot_b = 0;
		s = rd(); x = rd();
		for (int i = lg; i >= 0; --i) {
			if (!f[s][i][1] || (tot_a + tot_b + d[s][i][1].fir + d[s][i][1].sec > x)) continue;
			tot_b += d[s][i][1].fir;
			tot_a += d[s][i][1].sec;
			s = f[s][i][1];
		}
		printf("%lld %lld\n", tot_a, tot_b);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/xcysblog/p/9868559.html

时间: 2024-10-13 14:08:20

Luogu1081 开车旅行的相关文章

luogu1081 开车旅行 树上倍增

题目大意 小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i 的海拔高度为Hi,城市i 和城市j 之间的距离d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i,j] = |Hi – Hj|. 旅行过程中,小A和小B轮流开车,第一天小A开车,之后每天轮换一次.他们计划选择一个城市S作为起点,一直向东行驶,并且最多行驶X公里就结束旅行.小A和小B的驾驶风格不同,小B总是沿着前进方向选择一个最近的城市作

luogu1081 开车旅行2012 D1T3 (倍增,set,O2)

题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i,j] = |Hi? Hj|. 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次.他们计划选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行.小 A 和小 B的驾驶风

$Noip2012\ Luogu1081$ 开车旅行(倍增优化$ DP$)

Luogu Description Sol 1.发现对于每个城市,小A和小B的选择是固定的,可以预处理出来,分别记为ga[],gb[] 2.并且,只要知道了出发城市和出发天数,那么当前城市和小A,小B各行驶的路程也是一定的,同样可以分别预处理出来 具体怎么预处理: 1.其实就是"邻值查找"    简单讲一下,就是把所有城市的高度都存进set排好序,然后ga[i]一定是在set里与h[i]相邻的中最近的的,gb[i]是与h[i]相邻的中次近的 2.倍增优化: 1) 设$p[i][j][k

noip2012 开车旅行

P1081 开车旅行 139通过 484提交 题目提供者洛谷OnlineJudge 标签倍增2012NOIp提高组 难度提高+/省选- 提交该题 讨论 题解 记录 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi− Hj|. 旅行过程中,小

codevs 1199 开车旅行 2012年NOIP全国联赛提高组

1199 开车旅行 2012年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i, j] = |Hi − Hj|. 旅行过程中,小A 和小B轮流开

2012Noip提高组Day1 T3 开车旅行

题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi− Hj|. 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次.他们计划 选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行.小 A 和小 B

开车旅行

洛谷P1081 开车旅行  NOIP 2012 提高组 第一天 第三题 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi− Hj|. 旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次.他们计划 选择一个城市 S 作

洛谷P1081 开车旅行

P1081 开车旅行 152通过 524提交 题目提供者洛谷OnlineJudge 标签倍增NOIp提高组2012 难度省选/NOI- 提交该题 讨论 题解 记录 最新讨论 我前排提醒一下 题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即 d[i,j] = |Hi−

【题解】开车旅行

开车旅行 (drive.cpp/c/pas) [问题描述] 小A 和小B决定利用假期外出旅行,他们将想去的城市从1到N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i的海拔高度为Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i, j] = |???? − ????|. 旅行过程中,小A 和小B轮流开车,第一天小A 开车,之后每天轮换一次.他们计划选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X