1. 程式人生 > >洛谷 1442 鐵球落地

洛谷 1442 鐵球落地

核心思想:離散化 + 線段樹 + DP

離散化就不用說了(話說這題也沒給資料範圍),一套常規離散操作處理一下所有橫座標。

然後從低到高對每個板子線上段樹上做區間賦值,並預處理出每個板子的左右落點。

最後像數字三角形一樣做一下DP就好了。

DP的時候:

設dp[i][0/1]表示從左/右轉移上來的最大值,判斷縱向距離小於Max 就轉移.

方程:

if (a[i].h - a[a[i].ld].h <= Max) 
  if (a[i].ld)
    dp[i][0] = std::min(dp[a[i].ld][0] + cx[a[i].p] - cx[a[a[i].ld].p],
                dp[a[i].ld][1] + cy[a[a[i].ld].p] - cx[a[i].p])
                + a[i].h - a[a[i].ld].h; else dp[i][0] = a[i].h;
if (a[i].h - a[a[i].rd].h <= Max)
  if (a[i].rd)
    dp[i][1] = std::min(dp[a[i].rd][0] + cy[a[i].p] - cx[a[a[i].rd].p],
                dp[a[i].rd][1] + cy[a[a[i].rd].p] - cy[a[i].p])
                + a[i].h - a[a[i].rd].h; else dp[i][1] = a[i].h;

 

一些細節:

1.可以把鐵球初始位置和地面看作板子。

2.轉移的時候別忘了加上板子間的高度(我太傻了,調了三個小時就因為這個).

AC程式碼:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
inline void read(int & x)
{    int k = 1; x = 0; char
c = getchar(); while (!isdigit(c)) if (c == '-') c = getchar(), k = -1; else c = getchar(); while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); x *= k; } struct Node { int h, l, r, p, ld, rd; bool operator < (const Node & b) const { return h < b.h; }; } a[102020
]; struct Tree { int l, r, w; }t[808080]; #define lson l, mid, u << 1 #define rson mid + 1, r, u << 1 | 1 #define root 1, N, 1 #define ls u << 1 #define rs u << 1 | 1 inline void push_down(int u) { t[ls].w = t[u].w, t[rs].w = t[u].w; t[u].w = 0; } void build(int l, int r, int u) { t[u].l = l, t[u].r = r; if (l == r) return; int mid = (l + r) >> 1; build(lson); build(rson); } void Add(int u, int l, int r, int c) { if (t[u].l >= l && t[u].r <= r) { t[u].w = c; return; } if (t[u].w) push_down(u); int mid = (t[u].l + t[u].r) >> 1; if (l <= mid) Add(ls, l, r, c); if (r > mid) Add(rs, l, r, c); } int Query(int l, int r, int u, int x) { if (l == r && l == x) return t[u].w; if (t[u].w) push_down(u); int mid = l + r >> 1; if (x <= mid) return Query(lson, x); if (x > mid) return Query(rson, x); } int n, Max, fx, fy, N, h[101010], cx[102020], cy[102020], lx[202020], dp[102020][2]; signed main() { memset(dp, 0x3f, sizeof(dp)); read(n), read(Max), read(fx), read(fy); for (int i = 1; i <= n; ++i) read(a[i].h), read(cx[i]), read(cy[i]), lx[++N] = cx[i], lx[++N] = cy[i], a[i].p = i; lx[++N] = fx, a[n + 1].h = fy; cx[n + 1] = cy[n + 1] = fx; a[0].h = 0, a[0].p = 0, a[n + 1].p = n + 1; std::sort(lx + 1, lx + N + 1); for (int i = 1; i <= n + 1; ++i) a[i].l = std::lower_bound(lx + 1, lx + N + 1, cx[i]) - lx, a[i].r = std::lower_bound(lx + 1, lx + N + 1, cy[i]) - lx; std::sort(a + 1, a + n + 2); build(1, N, 1); for (int i = 1; i <= n + 1; ++i) a[i].ld = Query(root, a[i].l), a[i].rd = Query(root, a[i].r), Add(1, a[i].l, a[i].r, i); for (int i = 1; i <= n + 1; ++i) { if (a[i].h - a[a[i].ld].h <= Max) if (a[i].ld) dp[i][0] = std::min(dp[a[i].ld][0] + cx[a[i].p] - cx[a[a[i].ld].p], dp[a[i].ld][1] + cy[a[a[i].ld].p] - cx[a[i].p]) + a[i].h - a[a[i].ld].h; else dp[i][0] = a[i].h; if (a[i].h - a[a[i].rd].h <= Max) if (a[i].rd) dp[i][1] = std::min(dp[a[i].rd][0] + cy[a[i].p] - cx[a[a[i].rd].p], dp[a[i].rd][1] + cy[a[a[i].rd].p] - cy[a[i].p]) + a[i].h - a[a[i].rd].h; else dp[i][1] = a[i].h; } printf("%d", dp[n + 1][1]); }