题目链接
题目解法
由于费用均为正,在最优方案中不应存在没有起到作用的区间。
因此,可以考虑按照位置从左到右的顺序进行动态规划,每一步要求两个区间的左右端点可以连接上,以下是一份该算法的
实现。
#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;
}
可以注意到,该动态规划的本质是最短路,且每个点只会被松弛一次。
由此,用线段树维护尚未松弛的点,并用堆维护已经松弛的点即可快速模拟该过程。
时间复杂度 。
#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;
}