[link。](E - ふたつの料理 (Two Dishes) (atcoder.jp)

我要放假

神仙题。

首先可以把两根轴拉成平面(which is a common trick),把决策的过程看作从 \((0, 0)\) 走到 \((n, m)\),每次可以往上走或往右走(左下为 (0, 0),右上是 (n, m))。考虑相对于我们走出的决策路线表现出了怎样特征的点会对答案造成贡献。对于 A 套餐的操作 \(i\) 处理出 \(x_i\),表示做完了 A 套餐的前 i 个操作,最多还能做到 B 套餐的 x_i 操作,同理处理出 \(y_j\)。

把 \((i, x_i)\),\((y_j, j)\) 看作点放到平面上,当 \((i, x_i)\) 在路径上方是获得 \(p_i\) 的贡献,当 \((y_j, j)\) 在路径当中或下方时获得 \(q_j\) 的贡献。可以先把 p_i 全部加上然后取反转化调整到和 q_j 同样的贡献条件。

那么现在问题是:给出平面,找出一条从 (0, 0) 到 (n, m) 的路径,使得路径当中以及以下的点权和最大。

考虑 dp,设 \(f[i][j]\) 为走到 (i, j) 的最优答案。令 \(s[i][j]\) 为点 \((i, j)\) 正下方以及自己的点权和,然后我们发现无论从上一行还是上一列转移写出来都不对劲(\(dp[i][j] = dp[i-1][j]+f_1(i, j)+dp[i][j-1]+f_2(i, j)\) 的形式,不好优化),我们考虑从拐点转移(这一步很神奇,同时这一步也是我觉得整道题最 tricky 的地方,但是网上的题解都太草率了,给的转移也不能让我信服),写出的 transitions 是 \(\displaystyle dp[i][j] = \max_{k \leqslant j}\{dp[i-1][k]\}+s[i][j]\),自己画一个先右再上的折箭头就理解了。

考察转移发现我们有太多的无用转移,注意到平面中权重非 0 的点只有 \(O(n+m)\) 个,于是我们考虑非 0 点。首先把 s[i][j] 拆成 \(w_{0, j}+w_{1, j}+\dots +w_{i, j}\),这样我们的区间修改就是区间加定值而不是加一个毫无特征的序列了。再考虑前缀 max,因为我们是差分数组,我们只需要将 diff array 中的负项删除,并删除其影响,最后一位即是最大值。

/*
lyddnb
dp[i][j] = max[k <= j]{dp[i-1][k]}+s[i][j]
dp[i]: foreach j, j = premax, j += s[i][j]
*/
int n, m, p[1000100], q[1000100];
ll a[1000100], b[1000100], s[1000100], t[1000100], ans, dif[1000100];
vi<pil> g[1000100]; // g[i](x, y) point (i, x) with weight y
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> a[i] >> s[i] >> p[i], a[i] += a[i - 1];
for (int i = 1; i <= m; ++i) cin >> b[i] >> t[i] >> q[i], b[i] += b[i - 1];
for (int i = 1; i <= n; ++i) {
if (a[i] > s[i]) continue;
int j = upper_bound(b + 1, b + m + 1, s[i] - a[i]) - b;
ans += p[i], g[i].eb(j, -p[i]);
}
for (int i = 1; i <= m; ++i) {
if (b[i] > t[i]) continue;
if (b[i] + a[n] <= t[i])
ans += q[i];
else {
int j = upper_bound(a + 1, a + n + 1, t[i] - b[i]) - a;
g[j].eb(i, q[i]);
}
}
set<int> st;
for (int i = 0; i <= n; ++i) {
sort(g[i].begin(), g[i].end());
for (auto const& [x, y] : g[i]) {
if (x <= m) {
if (!st.count(x)) st.insert(x), dif[x] = 0;
dif[x] += y;
}
}
for (auto const& [x, ignore] : g[i]) {
if (x > m) continue;
auto it = st.find(x);
while (it != st.end() && dif[*it] < 0) {
ll tmp = dif[*it];
it = st.erase(it);
if (it != st.end()) dif[*it] += tmp;
}
}
}
for (auto x : st) ans += dif[x];
cout << ans << "\n";
}

「joisc 2019 - d2t2」ふたつの料理 Two Dishes的更多相关文章

  1. 【LOJ】#3034. 「JOISC 2019 Day2」两道料理

    LOJ#3034. 「JOISC 2019 Day2」两道料理 找出最大的\(y_{i}\)使得\(sumA_{i} + sumB_{y_i} \leq S_{i}\) 和最大的\(x_{j}\)使得 ...

  2. 「JOISC 2019 Day3」穿越时空 Bitaro

    「JOISC 2019 Day3」穿越时空 Bitaro 题解: ​ 不会处理时间流逝,我去看了一眼题解的图,最重要的转换就是把(X,Y)改成(X,Y-X)这样就不会斜着走了. ​ 问题变成二维平面上 ...

  3. 【LOJ】#3036. 「JOISC 2019 Day3」指定城市

    LOJ#3036. 「JOISC 2019 Day3」指定城市 一个点的可以dp出来 两个点也可以dp出来 后面的就是在两个点的情况下选一条最长的链加进去,用线段树维护即可 #include < ...

  4. 【LOJ】#3032. 「JOISC 2019 Day1」馕

    LOJ#3032. 「JOISC 2019 Day1」馕 处理出每个人把馕切成N段,每一段快乐度相同,我们选择第一个排在最前的人分给他的第一段,然后再在未选取的的人中选一个第二个排在最前的切一下,并把 ...

  5. 【LOJ】#3033. 「JOISC 2019 Day2」两个天线

    LOJ#3033. 「JOISC 2019 Day2」两个天线 用后面的天线更新前面的天线,线段树上存历史版本的最大值 也就是线段树需要维护历史版本的最大值,后面的天线的标记中最大的那个和最小的那个, ...

  6. 【LOJ】#3031. 「JOISC 2019 Day1」聚会

    LOJ#3031. 「JOISC 2019 Day1」聚会 听说随机可过? 我想了很久想了一个不会被卡的做法,建出前\(u - 1\)个点的虚树,然后找第\(u\)个点的插入位置,就是每次找一条最长链 ...

  7. 【LOJ】#3030. 「JOISC 2019 Day1」考试

    LOJ#3030. 「JOISC 2019 Day1」考试 看起来求一个奇怪图形(两条和坐标轴平行的线被切掉了一个角)内包括的点个数 too naive! 首先熟练的转化求不被这个图形包含的个数 -- ...

  8. @loj - 3039@ 「JOISC 2019 Day4」蛋糕拼接 3

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 今天是 IOI 酱的生日,所以她的哥哥 JOI 君给她预定了一个 ...

  9. 「JOISC 2019 Day4」蛋糕拼接 3

    loj 3039 NKOJ Description \(n\)个蛋糕,每个蛋糕有\(w_i,h_i\).选\(m\)个蛋糕满足\(\sum\limits_{j=1}^mw_{k_j}-\sum\lim ...

  10. 【LOJ】#3014. 「JOI 2019 Final」独特的城市(长链剖分)

    LOJ#3014. 「JOI 2019 Final」独特的城市(长链剖分) 显然我们画一条直径,容易发现被统计的只可能是直径某个距离较远的端点到这个点的路径上的值 用一个栈统计可以被统计的点,然后我们 ...

随机推荐

  1. C#设计模式19——装饰器模式的写法

    装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许你动态地给一个对象添加一些额外的职责,而不需要修改这个对象的代码. What(什么) 装饰器模式是一种结构型设计模式,它允许 ...

  2. Eclipse的Console如何实现中文输出(Eclipse Display Chinese)

    最近遇到Eclipse的Console中文输出乱码的问题,现象如下: 在网上找到一些方法,一般均不好用,直到找到"如何在Eclipse控制台中显示汉字",链接如下 https:// ...

  3. .Net7矢量化的性能优化

    前言 矢量化是性能优化的重要技术,也是寄托硬件层面的优化技术.本篇来看下. 概括 一:矢量化支持的问题: 矢量化的System.Runtime.Intrinsics.X86.Sse2.MoveMask ...

  4. 【城南】如何识别AI生成图?视觉AIGC伪造检测技术综述

    如何识别 AI 生成图片?or 如何识别 AIGC 图?or 如何识别 AI 换脸?or AI生成图伪造检测? 类似的说法有很多种,总之就是利用AI技术来鉴别一张图是不是AI生成的,这种AI技术就是本 ...

  5. java后端接入微信小程序登录功能

    前言 此文章是Java后端接入微信登录功能,由于项目需要,舍弃了解密用户信息的session_key,只保留openid用于检索用户信息 后端框架:spring boot 小程序框架:uniapp 流 ...

  6. StencilJs学习之事件

    其实并没有所谓的 stencil Event,相反 stencil 鼓励使用 DOM event.然而,Stencil 提供了一个 API 来指定组件可以触发的事件,以及组件监听的事件. 这是通过 E ...

  7. 深入了解ApacheZeppelin:如何构建高效的数据科学平台

    目录 引言 随着数据科学和人工智能的快速发展,如何构建高效的数据科学平台已经成为一个重要议题.Apache Zeppelin是一个开源的数据科学平台,其提供了一种简单.高效的方式来处理和存储数据,并且 ...

  8. 如何刷新 DNS 缓存 (macOS, Linux, Windows)

    如何刷新 DNS 缓存 (macOS, Linux, Windows) Unix Linux Windows 如何刷新 DNS 缓存 (macOS, FreeBSD, RHEL, CentOS, De ...

  9. React后台管理系统08 左侧菜单栏点击事件以及设置只有一个菜单展开项

    我们在Menu组件身上添加一个点击事件:对应的函数写一个回调函数:获取当前对象的e的身上的key, 这里其实不难看出e就是当前点击时的menu对象,我们这里获取的是e的key,对应上面定义的属性. 此 ...

  10. MySQL 存储引擎 InnoDB 内存结构之更改缓冲区

    更改缓冲区(Change Buffer)是一种特殊的数据结构,用于缓存不在缓冲池中的二级索引(secondary index)页的更改.可能来自于INSERT.UPDATE或DELETE操作(数据操作 ...