本文最后更新于 2024-08-29T16:36:32+08:00
Luogu
题意
给定一个由对数对描述的数组,每个数对 $(a_i, b_i)$ 表示 $a_i$ 个 $b_i$ 连续排列。每秒钟,所有索引为奇数或与前一个元素不同的元素会被删除。我们的目标是计算在数组变为空之前需要的秒数。
思路
考虑 dp。
处理每个数对,对于每个数对将其作为一个新的状态插入到队列中。在插入之前,需要检查队列的尾部元素是否与新状态冲突。冲突有两种情况:
- 如果尾部元素的连续数量小于或等于新状态的连续数量,说明尾部元素会在新状态开始之前就被删除。
- 如果尾部元素的开始位置与新状态相同,说明它们是连续的,我们需要将它们的连续数量合并。
处理完每个数对后,队列的第一个元素就是当前序列的状态。输出这个状态的连续数量,即当前序列变为空所需的秒数。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <bits/stdc++.h> #define int long long
using namespace std;
const int N = 3e5 + 5;
int T; int n, m; int a[N], b[N];
signed main() { scanf("%lld", &T); for (int i = 1; i <= T; ++i) { scanf("%lld", &n); for (int i = 0; i < n ; i++) { scanf("%lld%lld", &a[i], &b[i]); }
deque<pair<int, int>> dp;
for (int i = 0; i < n; ++i) { pair<int, int> newp = { b[i], a[i] }; int maxn = 0; while (dp.size() > 0 && (dp.back().second <= newp.second || dp.back().first == newp.first)) { if (dp.back().first == newp.first) { newp.second = dp.back().second + newp.second - maxn; } maxn = dp.back().second; dp.pop_back(); }
dp.push_back(newp); printf("%lld ", dp[0].second); } printf("\n"); } return 0; }
|