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;
}

浙公网安备 33010602011771号