1 条题解
-
0
问题具有显著的阶段性,考虑 DP,设 表示前 个人操作后造成的最大伤害。
首先有直接攻击的转移 。在此之外,我们还可以找到一个 ,并且找到一个 ,使得 ,转移为 。
考虑记 $s_{q_j} = \{(p_j, c_j)\}, u_{p_j} = \max_{a_k = p_j} \{f_{k - 1}\}$,每次枚举 并转移 即可。 维护 是简单的。时间复杂度 ,可以达到 ,不能通过。
我们注意到满足 的 一定不超过 个。考虑仅在 中保留 的 ,这时上述转移复杂度降到 ;而对于剩下的 记 ,那么一定有 。
仅对于在 中的 设 $v_{q_j} = \max_{(p_j, q_j, c_j), a_k = p_j} \{f_{k - 1} + c_j\}$,转移时直接 即可。维护 可以枚举 ,有 ,时间复杂度 。总时间复杂度 $\mathcal{O}(1 + \frac{m}{B}) = \mathcal{O}(\frac{m}{B})$。
综上,时间复杂度为 ,显然 时取得最小值 。
这一方法是一种似乎并不常见的动态规划优化,称为根号分治优化 DP,有较高的思维难度。
Code:
#include<bits/stdc++.h> #define mem(a, v) memset(a, v, sizeof(a)) using namespace std; const int maxn = 2e5 + 10, maxm = 2e5 + 10, maxx = 2e5 + 10, maxy = 2e5 + 10, gap = 5e2; int n, m, x, y; int d[maxx], a[maxn], b[maxn], p[maxm], q[maxm], c[maxm], cnt[maxx]; long long u[maxy], v[maxx], f[maxn]; vector<pair<int, int> > s[maxx], t[maxy]; int main(){ scanf("%d %d %d %d", &n, &m, &x, &y); for (int i = 1; i <= x; i++){ scanf("%d", &d[i]); } for (int i = 1; i <= n; i++){ scanf("%d %d", &a[i], &b[i]); } for (int i = 1; i <= m; i++){ scanf("%d %d %d", &p[i], &q[i], &c[i]); cnt[q[i]]++; } for (int i = 1; i <= m; i++){ if (cnt[q[i]] > gap){ t[p[i]].emplace_back(q[i], c[i]); }else{ s[q[i]].emplace_back(p[i], c[i]); } } mem(u, -0x3f), mem(v, -0x3f); for (int i = 1; i <= n; i++){ f[i] = f[i - 1] + d[b[i]]; if (cnt[b[i]] > gap){ f[i] = max(f[i], v[b[i]] + d[b[i]]); }else{ for (auto x: s[b[i]]){ f[i] = max(f[i], u[x.first] + x.second + d[b[i]]); } } u[a[i]] = max(u[a[i]], f[i - 1]); for (auto x: t[a[i]]){ v[x.first] = max(v[x.first], f[i - 1] + x.second); } } printf("%lld", f[n]); return 0; }
- 1
信息
- ID
- 7426
- 时间
- 500ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者