1 条题解
-
0
自动搬运
来自洛谷,原作者为

w33z8kqrqk8zzzx33
**搬运于
2025-08-24 22:33:14,当前版本为作者最后更新于2021-10-27 22:27:30,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
首先,题目描述过于抽象,本质是求 的一个子序列,使得这个子序列包含 ,并且子序列中相邻的元素位置距离 ,并且从前往后破纪录元素尽量多,求破纪录元素个数。
只有 相对顺序有用,所以先将 离散化。
考虑 dp,其中 为 为破纪录元素时能包含几个破纪录元素。 肯定为破纪录元素,所以我们需要枚举在 前面的第一个破纪录元素 。则 。而为了保证存在一个子序列包含 和 ,还满足相邻元素距离 ,必须存在 使得
- (来保证 是破纪录元素,注意不需要保证这些小于 ,因为这样肯定不优)
则可以取所有满足条件的 并且求 。直接 dp 可以做到 。而发现由于 时 的大量变化,维护相邻元素距离约束相对困难,于是考虑对 扫描线。
按照 从小到大更新 ,则计算某个 的时候肯定只有已经被更新的 能影响 。
我们维护一个 set 包含所有已经被更新的位置:这些位置上的值均小于 。维护一个并查集,其中 和 连通当且仅当 和 被更新并且 ,则可以从并查集的连通块信息得出任何 的最左端 使得相邻元素距离约束成立。
然后用并查集得到 之后用线段树维护 区间最大值,总共时间复杂度 :
#include <bits/stdc++.h> using namespace std; #define all(a) a.begin(), a.end() #define fi first #define se second #define pb push_back #define mp make_pair using ll = long long; using pii = pair<int, int>; //#define int ll const int MOD = 1000000007; int las[300005]; int ufs(int u) { if (las[u] == -1) return u; return las[u] = ufs(las[u]); } void conn(int u, int v) { u = ufs(u), v = ufs(v); if (u != v) las[max(u, v)] = min(u, v); } int seg[300005 << 2]; void upd(int idx, int l, int r, int u, int v) { if (!(l <= u && u < r)) return; if (r - l == 1) { seg[idx] = v; return; } upd(idx * 2, l, (l + r) / 2, u, v); upd(idx * 2 + 1, (l + r) / 2, r, u, v); seg[idx] = max(seg[idx * 2], seg[idx * 2 + 1]); } int qry(int idx, int l, int r, int L, int R) { if (L <= l && r <= R) return seg[idx]; if (R <= l || r <= L) return 0; return max(qry(idx * 2, l, (l + r) / 2, L, R), qry(idx * 2 + 1, (l + r) / 2, r, L, R)); } signed main() { ios_base::sync_with_stdio(false); cin.tie(0); memset(las, -1, sizeof las); int n, d; cin >> n >> d; vector<pii> x(n); for (int i = 0; i < n; i++) cin >> x[i].fi, x[i].se = -i; sort(all(x)); set<int> on; int ans = 0; for (auto [_, i] : x) { i = -i; auto pos = on.insert(i).fi; if (pos != on.begin() && *pos - *prev(pos) <= d) conn(*pos, *prev(pos)); if (next(pos) != on.end() && *next(pos) - *pos <= d) conn(*pos, *next(pos)); int dp = qry(1, 0, n, ufs(i), i) + 1; ans = max(ans, dp); upd(1, 0, n, i, dp); } cout << ans << endl; }
- 1
信息
- ID
- 6863
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者