【LOJ3282】「JOISC 2020 Day4」治疗计划

题目链接

点击打开链接

题目解法

由于费用均为正,在最优方案中不应存在没有起到作用的区间。
因此,可以考虑按照位置从左到右的顺序进行动态规划,每一步要求两个区间的左右端点可以连接上,以下是一份该算法的 O ( N 2 ) O(N^2) 实现。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const long long INF = 1e18;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
bool vis[MAXN]; ll dp[MAXN];
int n, m, t[MAXN], l[MAXN], r[MAXN], c[MAXN];
int find() {
	ll ans = INF; int home = 0;
	for (int i = 1; i <= m; i++)
		if (!vis[i] && dp[i] < ans) {
			ans = dp[i];
			home = i;
		}
	return home;
}
int main() {
	read(n), read(m);
	for (int i = 1; i <= m; i++) {
		read(t[i]), read(l[i]), read(r[i]), read(c[i]);
		if (l[i] == 1) dp[i] = c[i];
		else dp[i] = INF;
	}
	for (int pos = find(); pos != 0; pos = find()) {
		vis[pos] = true;
		for (int i = 1; i <= m; i++)
			if (r[pos] - l[i] + 1 >= abs(t[i] - t[pos])) chkmin(dp[i], dp[pos] + c[i]);
	}
	ll ans = INF;
	for (int i = 1; i <= m; i++)
		if (r[i] == n) chkmin(ans, dp[i]);
	if (ans == INF) puts("-1");
	else cout << ans << endl;
	return 0;
}

可以注意到,该动态规划的本质是最短路,且每个点只会被松弛一次。
由此,用线段树维护尚未松弛的点,并用堆维护已经松弛的点即可快速模拟该过程。

时间复杂度 O ( M L o g M ) O(MLogM)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const long long INF = 1e18;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
struct info {int t, l, r, c; };
int n, m; info a[MAXN]; ll dp[MAXN];
priority_queue <pair <ll, int>, vector <pair <ll, int>>, greater <pair <ll, int>>> Heap;
struct SegmentTree {
	struct Node {
		int lc, rc;
		int Minx, Miny;
	} a[MAXN * 2];
	int n, root, size;
	void build(int &root, int l, int r) {
		root = ++size;
		if (l == r) return;
		int mid = (l + r) / 2;
		build(a[root].lc, l, mid);
		build(a[root].rc, mid + 1, r);
	}
	void init(int x) {
		n = x, root = size = 0;
		build(root, 1, n);
	}
	void update(int root) {
		a[root].Minx = min(a[a[root].lc].Minx, a[a[root].rc].Minx);
		a[root].Miny = min(a[a[root].lc].Miny, a[a[root].rc].Miny);
	}
	void modify(int root, int l, int r, int pos, int x, int y) {
		if (l == r) {
			a[root].Minx = x;
			a[root].Miny = y;
			return;
		}
		int mid = (l + r) / 2;
		if (mid >= pos) modify(a[root].lc, l, mid, pos, x, y);
		else modify(a[root].rc, mid + 1, r, pos, x, y);
		update(root);
	}
	void modify(int pos, int x, int y) {
		modify(root, 1, n, pos, x, y);
	}
	void queryx(int root, int l, int r, int ql, int qr, int v, vector <int> &res) {
		if (a[root].Minx > v) return;
		if (l == ql && r == qr) {
			if (l == r) {
				res.push_back(l);
				a[root].Minx = a[root].Miny = INT_MAX;
				return;
			}
			int mid = (l + r) / 2;
			queryx(a[root].lc, l, mid, l, mid, v, res);
			queryx(a[root].rc, mid + 1, r, mid + 1, r, v, res);
			update(root);
			return;
		}
		int mid = (l + r) / 2;
		if (mid >= qr) queryx(a[root].lc, l, mid, ql, qr, v, res);
		else if (mid + 1 <= ql) queryx(a[root].rc, mid + 1, r, ql, qr, v, res);
		else queryx(a[root].lc, l, mid, ql, mid, v, res), queryx(a[root].rc, mid + 1, r, mid + 1, qr, v, res);
		update(root);
	}
	void queryx(int l, int r, int v, vector <int> &res) {
		if (l > r) return;
		else queryx(root, 1, n, l, r, v, res);
	}
	void queryy(int root, int l, int r, int ql, int qr, int v, vector <int> &res) {
		if (a[root].Miny > v) return;
		if (l == ql && r == qr) {
			if (l == r) {
				res.push_back(l);
				a[root].Minx = a[root].Miny = INT_MAX;
				return;
			}
			int mid = (l + r) / 2;
			queryy(a[root].lc, l, mid, l, mid, v, res);
			queryy(a[root].rc, mid + 1, r, mid + 1, r, v, res);
			update(root);
			return;
		}
		int mid = (l + r) / 2;
		if (mid >= qr) queryy(a[root].lc, l, mid, ql, qr, v, res);
		else if (mid + 1 <= ql) queryy(a[root].rc, mid + 1, r, ql, qr, v, res);
		else queryy(a[root].lc, l, mid, ql, mid, v, res), queryy(a[root].rc, mid + 1, r, mid + 1, qr, v, res);
		update(root);
	}
	void queryy(int l, int r, int v, vector <int> &res) {
		if (l > r) return;
		else queryy(root, 1, n, l, r, v, res);
	}
} ST;
int main() {
	read(n), read(m);
	for (int i = 1; i <= m; i++) {
		read(a[i].t), read(a[i].l);
		read(a[i].r), read(a[i].c);
	}
	sort(a + 1, a + m + 1, [&] (info a, info b) {return a.t < b.t; });
	ST.init(m);
	for (int i = 1; i <= m; i++) {
		if (a[i].l == 1) {
			dp[i] = a[i].c;
			Heap.emplace(a[i].c, i);
			ST.modify(i, INT_MAX, INT_MAX);
		} else {
			dp[i] = INF;
			ST.modify(i, a[i].l - a[i].t, a[i].l + a[i].t);
		}
	}
	while (!Heap.empty()) {
		int pos = Heap.top().second; Heap.pop();
		vector <int> trans;
		ST.queryx(1, pos - 1, a[pos].r + 1 - a[pos].t, trans);
		ST.queryy(pos + 1, m, a[pos].r + 1 + a[pos].t, trans);
		for (auto x : trans) {
			dp[x] = dp[pos] + a[x].c;
			Heap.emplace(dp[x], x);
		}
	}
	ll ans = INF;
	for (int i = 1; i <= m; i++)
		if (a[i].r == n) chkmin(ans, dp[i]);
	if (ans == INF) puts("-1");
	else cout << ans << endl;
	return 0;
}
发布了813 篇原创文章 · 获赞 93 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/105074799