Luogu P7302 [NOI1998] 免费的馅饼 题解 [ 蓝 ] [ 二维偏序 ] [ 树状数组优化 DP ]

免费的馅饼:DMY 某比赛的原题,赛时没调出来树套树也是糖丸了。

首先这题长的就很像一个数据结构优化 DP 的东西,于是直接考虑 DP:定义 \(dp_i\) 表示到第 \(i\) 个馅饼时的最大得分。列出转移方程式,发现能从 \(dp_j\) 转移需要满足以下条件:

  • \(t_j \le t_i\)
  • \(\dfrac{|p_i - p_j|}{2}\le t_i-t_j\)

因为第二个条件左边是一个绝对值,所以 \(t_i = t_j\) 恒为非负,第一个条件就直接被第二个条件包含了。

所以我们直接对第二个条件考虑,先套路地拆绝对值

  • \(2t_j-p_j \le 2t_i-p_i(p_i\ge p_j)\)
  • \(2t_j+p_j \le 2t_i+p_i(p_i< p_j)\)

一个显然的思路是第一维以 \(p\) 的大小排序,然后后两维直接 CDQ 优化 DP 或者树套树优化 DP 就能 \(O(n\log^2 n)\) 冲过去。

观察一下还能不能把偏序条件简化,发现在忽略 \(p\) 的限制后,当这两个条件中任意一个成立时,另一个都成立。以第一个条件成立时为例,将两式移项:

  • \(p_i-p_j \le 2t_i-2t_j\)
  • \(p_j-p_i \le 2t_i-2t_j\)

因为第一个条件的前置条件是 \(p_i\ge p_j\),所以第二个条件此时一定成立,所以可以直接将两个条件进行合并,忽略 \(p\) 的限制,只有上述两个条件同时满足时才进行转移即可。

剩下的就是个很板的二维偏序了,直接上 BIT 即可。时间复杂度 \(O(n\log n)\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 100005;
ll n, m, b[N], bn, dp[N], ans;
struct Node{
    ll t, pos, v, x, y;
    bool operator < (const Node & a) const{
        return (x < a.x);
    }
}a[N];
int getid(ll x)
{
    return (lower_bound(b + 1, b + bn + 1, x) - b);
}
int lowbit(int x)
{
    return (x & (-x));
}
struct BIT{
    ll tr[N];
    void update(int p, ll v)
    {
        while(p <= bn)
        {
            tr[p] = max(tr[p], v);
            p += lowbit(p);
        }
    }
    ll query(int p)
    {
        ll res = 0;
        while(p)
        {
            res = max(res, tr[p]);
            p -= lowbit(p);
        }
        return res;
    }
}tr1;
int main()
{
    //freopen("sample.in", "r", stdin);
    //freopen("sample.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> m >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i].t >> a[i].pos >> a[i].v;
        a[i].x = 2 * a[i].t - a[i].pos;
        a[i].y = 2 * a[i].t + a[i].pos;
        b[++bn] = a[i].y;
    }
    sort(a + 1, a + n + 1);
    sort(b + 1, b + n + 1);
    bn = unique(b + 1, b + n + 1) - b - 1;
    for(int i = 1; i <= n; i++)
    {
        dp[i] = tr1.query(getid(a[i].y)) + a[i].v;
        tr1.update(getid(a[i].y), dp[i]);
        ans = max(ans, dp[i]);
    }
    cout << ans;
    return 0;
}
posted @ 2025-08-17 12:14  KS_Fszha  阅读(8)  评论(0)    收藏  举报