1 条题解
-
0
分析
转化
考虑两条线段 和 。我们将它们在 轴上的端点坐标记为 ,在顶部直线 上的端点坐标记为 。
题目保证所有 互不相同,所有 也互不相同。因此,线段 和线段 在同一个坐标系中不相交,当且仅当它们的端点在 轴上的顺序与在 上的顺序相同。
简单来说,如果我们把线段按照 (即 轴坐标)从小到大排序,那么它们对应的 (即顶部坐标)也必须是单调递增的,否则就会出现交叉。
形式化地,对于两条线段 和 ,假设 。它们不相交的充要条件是 。如果 ,则这两条线段必然相交。
例如,对于输入:
1 3 3 1第一条线段连接 和 ,第二条线段连接 和 。 这里有 ,但 。因此它们在同一个坐标系中会相交,必须分开放置,所以答案是 。
序列问题
根据上述分析,问题转化如下:
将所有线段按底部端点坐标 升序排序,得到一个新的顶部端点坐标的序列 。我们要将这个序列划分成尽可能少的子序列,使得每个子序列都是严格递增的。
根据 Dilworth 定理,一个序列最少能划分成的递增子序列的数量,等于其最长不升子序列的长度。因此,我们的目标就是求出排序后序列 的最长不升子序列的长度。
由于 ,我们需要一个 的算法。
实现
我们使用经典的贪心加二分的方法。
设原数组为 ,我们希望找到 的最长不升子序列。将其取反得到数组 ,其中 。那么 的一个不升子序列 对应到 上就是 ,这是一个不降子序列。
因此,原问题转化为求数组 的最长不降子序列(LNDS)。
对于 LNDS,我们维护一个数组 ,其中 表示当前找到的长度为 的不降子序列的最小末尾元素。当我们处理一个新元素 时,在 中二分查找第一个大于 的位置。如果存在,则用 替换该元素;否则将 追加到 末尾。
最终 的长度即为答案。
细节说明:由于题目保证所有的 互不相同,序列 中没有重复元素,此时不降子序列等价于严格上升子序列。因此,可以使用
std::lower_bound来求最长上升子序列的长度,这与求最长不降子序列在本题条件下是等价的。代码
#include<bits/stdc++.h> #define ll long long #define endl "\n" #define bye return 0 #define hello ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) #define i_ak_all int main() using namespace std; i_ak_all{ hello; ll n; cin >> n; vector<ll> b(n), dp; vector<pair<ll, ll>> a(n); for (auto & x : a){ cin >> x.first >> x.second; } sort(a.begin(), a.end()); for (int i = 0; i < n; i++){ b[i] = -a[i].second; } for (ll x : b){ auto it = lower_bound(dp.begin(), dp.end(), x); if (it == dp.end()){ dp.push_back(x); } else { *it = x; } } cout << dp.size(); bye; }AI 使用说明:
本文在写作完成后使用 DeepSeek 进行了润色。
- 1
信息
- ID
- 3624
- 时间
- 1000ms
- 内存
- 64MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者