AtCoder Beginner Contest 353 abc353 G - Merchant Takahashi 题解
题意
AtCoder Beginner Contest 353 abc353 G - Merchant Takahashi
有 个城镇和 个活动依次发生,第 个活动在第 个城镇举办,你如果参加则可获得 的受益。你从 城镇移动到 城镇需要花费 。求最大受益。
思路
这道题能够轻松的写出 的dp写法。设 为举行了前 个活动,并且最终在第 个城镇时候的最大受益。
这里我们发现其实枚举第 个活动时候,只需要考虑最终在第 个城镇就好。这时候复杂度就降为了 ,方程变为了
优化第一维就变成了
但复杂度依旧很高,继续考虑,尝试把绝对值符号给拆开,方程变为
即
这里问题就变为了快速获取 与 中的最大值,而线段树可以完成这个事,我们可以建2个线段树来维护区间最大值。
一个树维护
一个树维护
线段树的复杂度是 ,最终整体复杂度为 。
代码
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#include <bitset>
#include <numeric>
#define fi first
#define se second
#define endl '\n'
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const ull P = 131;
const double eps = 1e-4;
const int N = 2e5 + 10;
// 线段树
struct SegmentTree {
struct Node{
int l, r;
ll sum;
};
vector<Node> tr;
void init(int n, vector<ll> &a) {
tr.resize(n * 4 + 1);
build(1, 1, n, a);
}
inline int lchild(int u) {
return u << 1;
}
inline int rchild(int u) {
return u << 1 | 1;
}
void pushup(int u) {
tr[u].sum = max(tr[lchild(u)].sum, tr[rchild(u)].sum);
}
void build(int u, int l, int r, vector<ll> &a) {
if(l == r) tr[u] = {l, r, a[l]};
else {
tr[u] = {l, r};
int mid = (l + r) >> 1;
build(lchild(u), l, mid, a), build(rchild(u), mid+1, r, a);
pushup(u);
}
}
void modify(int u, int x, ll v) {
if(tr[u].l == tr[u].r) {
tr[u].sum = max(tr[u].sum, v);
}
else {
int mid = (tr[u].l + tr[u].r) >> 1;
if(x <= mid) modify(lchild(u), x, v);
else modify(rchild(u), x, v);
pushup(u);
}
}
ll query(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
int mid = (tr[u].l + tr[u].r) >> 1;
ll res = -inf;
if(l <= mid) res = max(res, query(lchild(u), l, r));
if(r > mid) res = max(res, query(rchild(u), l, r));
return res;
}
};
int n, m;
ll c;
pair<int, ll> mar[N];
ll f[N];
void solve() {
scanf("%d%lld%d", &n, &c, &m);
for (int i=1; i<=m; i++) {
scanf("%d%lld", &mar[i].fi, &mar[i].se);
}
vector<ll> a(n + 1, -inf);
SegmentTree tr_l, tr_r;
a[1] = c;
tr_l.init(n, a);
a[1] = -c;
tr_r.init(n, a);
ll res = 0;
for (int i=1; i<=m; i++) {
auto [t, p] = mar[i];
ll dp1 = tr_l.query(1, 1, t) - c * t;
ll dp2 = tr_r.query(1, t, n) + c * t;
f[i] = max(dp1, dp2) + p;
res = max(res, f[i]);
tr_l.modify(1, t, f[i] + c * t);
tr_r.modify(1, t, f[i] - c * t);
}
printf("%lld\n", res);
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
// multiple case
// int t; scanf("%d", &t);
// while(t--) {
// solve();
// }
// single case
solve();
return 0;
}
不忘初心方得始终
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2023-05-17 AtCoder Beginner Contest 102 D - Equal Cut 题解