题解 - 「MLOI」小兔叽
小兔叽
\(\texttt{Link}\)
简单题意
有 \(n\) 个小木桩排成一行,第 \(i\) 个小木桩的高度为 \(h_i\),分数为 \(c_i\)。
如果一只小兔叽在第 \(i\) 个小木桩上,她会获得 \(c_i\) 的分数;同时,如果 \((|i - j| \neq 1) \wedge (h_j < h_i) \wedge (\forall \min\{i, j\} < k < \max\{i, j\}, h_k < h_i)\),那么她可以从第 \(i\) 个小木桩跳跃到第 \(j\) 个小木桩上;当然,她也可以停止跳跃。
记 \(f_i\) 表示小兔叽从第 \(i\) 个小木桩开始跳跃获得的总分数的最大值。
请你求出 \(\sum\limits_{i = 1}^{n} f_i\) 和 \(\mathrm{xor} _ {i = 1} ^ {n} |f_i|\)。
数据范围
对于 \(100\%\) 的数据:满足 \(1 \leq n \leq {3 \times 10^6}\),\(\forall 1 \leq i \leq n, \ 1 \leq h_i \leq {10}^{18} \wedge |c_i| \leq {10}^{10}\)。
\(\texttt{Solution}\)
由于小兔叽只能往低处跳,考虑建一棵笛卡尔树,满足大根堆性质,即 \(h_{f_u} \geq h_u\)。
- \(\texttt{lson[u]}\) 表示 \(u\) 的左儿子。
- \(\texttt{rson[u]}\) 表示 \(u\) 的右儿子。
\(\texttt{code}\):
void build(int u)
{
while (top && h[u] > h[S[top]]) lson[u] = S[top--];
rson[S[top]] = u; S[++top] = u;
}
其中 \(\texttt{h[u] > h[S[top]]}\) 可以使得 \(h_{f_u} = h_u\) 的取等条件为 \(\texttt{rson[f[u]] = u}\);当然如也写成 \(\texttt{h[u] >= h[S[top]]}\),这样取等条件就为 \(\texttt{lson[f[u]] = u}\)。
考虑 \(\texttt{dp}\):
- 定义 \(L_u\) 表示以 \(u\) 为根的子树对应的区间的左端点。
- 定义 \(R_u\) 表示以 \(u\) 为根的子树对应的区间的右端点。
- 定义 \(f_u\) 表示小兔叽从第 \(u\) 个小木桩开始跳跃获得的总分数的最大值。
- 定义 \(g_u\) 表示 \(\max\{f_i \ | \ L_u < i < R_u \}\),严格小于,即不包含两个端点。
考虑一个结点 \(u\) 的状态转移:
\(g_u\) 和初始值为 \(0\),\(f_u\) 初始值为 \(c_u\)。
考虑左儿子:
- \(g_u = \max\{ g_u, g_{\texttt{lson[u]}} \}\)
- \(g_u = \max\{ g_u, g_{u - 1}\}, {u - 1} > L_u\)
- \(f_u = \max\{ f_u, c_u + g_{\texttt{lson[u]}} \}, {u - 1} > L_u\)
- \(f_u = \max\{ f_u, c_u + f_{L_u} \}, {u - 1} > L_u\)
考虑右儿子:
\(g_u = \max\{ g_u, g_{\texttt{rson[u]}} \}\)
\(g_u = \max\{ g_u, g_{u + 1} \}, {u + 1} > R_u\)
条件 \({h_{\texttt{rson[u]}} = u} \wedge {\texttt{rson[u]} > {u + 1}}\):
- \(f_u = \max\{ f_u, c_u + g_{\texttt{lson[rson[u]]}} \}\)
- \(f_u = \max\{ f_u, c_u + f_{\texttt{rson[u]} - 1}\}, {\texttt{rson[u]} - 1} > {u + 1}\)
条件 \({h_{\texttt{rson[u]}} \neq u} \wedge {{u + 1} < R_u}\)
- \(f_u = \max\{ f_u, c_u + g_{\texttt{rson[u]}} \}\)
- \(f_u = \max\{ f_u, c_u + g_{R_u} \}\)
条件 \({{u + 1} < R_u}\)
考虑 \(u\) 自己:
- \(g_u = \max\{ g_u, f_u \}, L_u < u < R_u\)
上面与 \(L_u\) 和 \(R_u\) 有关的判断,就是在 \(\texttt{check}\) 与 \(u\) 相邻的结点可不可以对 \(g_u\) 或 \(f_u\) 做贡献。
因为建笛卡尔树的代码中写的是 \(\texttt{h[u] > h[S[top]]}\),所以只可能出现 \(h_{\texttt{rson[u]} = h_u}\),不会出现 \(h_{\texttt{lson[u]} = h_u}\)。
注意事项:
- \(f_u\) 是在 \(\texttt{long long}\) 范围内的,而 \(\sum\limits_{u = 1}^{n} f_u\) 可能会超出范围。
- 因为 \(\sum\limits_{u = 1}^{n} f_u\) 超出的范围不会很多,所以令 \(\texttt{mod} = {10}^{18}\) 压 \(2\) 位就可以了。
- 压位的时候记住要补 \(0\),同时不要出现前导 \(0\)。
- 使用题目给出的输入方式,不使用可能会 \(\texttt{TLE}\)。
\(\texttt{code}\)
#include <cstdio>
#include <cassert>
#define int long long
#define uint unsigned int
namespace Read
{
static const int buf_size = 1 << 12;
static unsigned char buf[buf_size];
static int buf_len = 0, buf_pos = 0;
inline bool isEOF()
{
if (buf_pos == buf_len)
{
buf_pos = 0; buf_len = fread(buf, 1, buf_size, stdin);
if (buf_pos == buf_len) return true;
}
return false;
}
inline char readChar()
{
return isEOF() ? EOF : buf[buf_pos++];
}
inline int rint()
{
int x = 0, fx = 1; char c = readChar();
while (c < '0' || c > '9') { fx ^= (c == '-'); c = readChar(); }
while ('0' <= c && c <= '9') { x = (x << 3) + (x << 1) + (c ^ 48); c = readChar(); }
if (!fx) return -x;
return x;
}
inline void read(int &x)
{
x = rint();
}
template<typename... Ts>
inline void read(int &x, Ts &...rest)
{
x = rint();
read(rest...);
}
} using namespace Read;
namespace Write
{
static const int buf_size = 1 << 12;
static char buf[buf_size];
static int buf_pos = 0;
inline void flush()
{
if (buf_pos)
{
fwrite(buf, 1, buf_pos, stdout);
buf_pos = 0; fflush(stdout);
}
}
inline void writeChar(char x)
{
if (buf_pos == buf_size)
{
fwrite(buf, 1, buf_size, stdout);
buf_pos = 0;
}
buf[buf_pos++] = x;
}
inline void write(int x, char end = 0)
{
if (x < 0) { writeChar('-'); x = -x; }
char str[24]; int n = 0;
do { str[n++] = ((x % 10) ^ 48); x /= 10; } while (x);
while (n--) writeChar(str[n]);
if (end) writeChar(end);
flush();
}
} using namespace Write;
namespace Math
{
int Max(int u, int v) { return (u > v) ? u : v; }
int Min(int u, int v) { return (u < v) ? u : v; }
} using namespace Math;
const int inf = 1e18;
const int mod = 1e18;
const int MAX_n = 3e6;
int n, top;
int h[MAX_n + 5];
int c[MAX_n + 5];
int S[MAX_n + 5];
int L[MAX_n + 5];
int R[MAX_n + 5];
int lson[MAX_n + 5];
int rson[MAX_n + 5];
int dp[MAX_n + 5];
int dpp[MAX_n + 5];
bool vis[MAX_n + 5];
void build(int u)
{
while (top && h[u] > h[S[top]]) lson[u] = S[top--];
rson[S[top]] = u; S[++top] = u;
}
void tree_dp(int u)
{
L[u] = R[u] = u;
if (lson[u])
{
tree_dp(lson[u]);
L[u] = L[lson[u]];
if (u - 1 > L[u])
{
dp[u] = Max(dp[u], dpp[lson[u]]);
dp[u] = Max(dp[u], dp[L[u]]);
dpp[u] = Max(dpp[u], dp[u - 1]);
}
dpp[u] = Max(dpp[u], dpp[lson[u]]);
}
if (rson[u])
{
tree_dp(rson[u]);
R[u] = R[rson[u]];
if (h[rson[u]] == h[u])
{
int v = rson[u];
if (v > u + 1)
{
dp[u] = Max(dp[u], dpp[lson[v]]);
if (v - 1 > u + 1) dp[u] = Max(dp[u], dp[v - 1]);
}
}
else if (u + 1 < R[u]);
{
dp[u] = Max(dp[u], dpp[rson[u]]);
dp[u] = Max(dp[u], dp[R[u]]);
}
dpp[u] = Max(dpp[u], dpp[rson[u]]);
if (u + 1 < R[u]) dpp[u] = Max(dpp[u], dp[u + 1]);
}
dp[u] += c[u];
if (L[u] < u && u < R[u])
dpp[u] = Max(dpp[u], dp[u]);
}
signed main()
{
freopen("jump.in", "r", stdin);
freopen("jump.out", "w", stdout);
n = rint();
assert(1 <= n && n <= MAX_n);
for (int i = 1; i <= n; build(i++))
{
read(h[i], c[i]);
assert(1 <= h[i] && h[i] <= 1e18);
assert(-1e10 <= c[i] && c[i] <= 1e10);
}
tree_dp(rson[0]);
int res_first = 0, res_second = 0, res_xor = 0;
for (int i = 1; i <= n; i++)
{
int now = dp[i];
res_first += (res_second + now) / mod;
res_second = (res_second + now) % mod;
res_xor ^= ((now > 0) ? now : -now);
}
if (!res_first) printf("%lld %lld\n", res_second, res_xor);
else printf("%lld%018lld %lld\n", res_first, res_second, res_xor);
return 0;
}
题解 - 「MLOI」小兔叽的更多相关文章
- loj#2009.「SCOI2015」小凸玩密室
题目链接 loj#2009. 「SCOI2015」小凸玩密室 题解 树高不会很高<=20 点亮灯泡x,点亮x的一个子树,再点亮x另外的子树, 然后回到x的父节点,点亮父节点之后再点亮父节点的其他 ...
- 「NOI2013」小 Q 的修炼 解题报告
「NOI2013」小 Q 的修炼 第一次完整的做出一个提答,花了半个晚上+一个上午+半个下午 总体来说太慢了 对于此题,我认为的难点是观察数据并猜测性质和读入操作 我隔一会就思考这个sb字符串读起来怎 ...
- 「SCOI2015」小凸想跑步 解题报告
「SCOI2015」小凸想跑步 最开始以为和多边形的重心有关,后来发现多边形的重心没啥好玩的性质 实际上你把面积小于的不等式列出来,发现是一次的,那么就可以半平面交了 Code: #include & ...
- 「SCOI2015」小凸解密码 解题报告
「SCOI2015」小凸解密码 题意:给一个环,定义一段连续的极长\(0\)串为\(0\)区间,定义一个位置的离一个\(0\)区间的距离为这个位置离这个区间中\(0\)的距离的最小值,每次询问一个位置 ...
- 「SCOI2015」小凸玩矩阵 解题报告
「SCOI2015」小凸玩矩阵 我好沙茶啊 把点当边连接行和列,在外面二分答案跑图的匹配就行了 我最开始二分方向搞反了,样例没过. 脑袋一抽,这绝壁要费用流,连忙打了个KM 然后wa了,一想这个不是完 ...
- 「SCOI2015」小凸玩密室 解题报告
「SCOI2015」小凸玩密室 虽然有心里在想一些奇奇怪怪的事情的原因,不过还是写太久了.. 不过这个题本身也挺厉害的 注意第一个被点亮的是任意选的,我最开始压根没注意到 \(dp_{i,j}\)代表 ...
- LibreOJ #2006. 「SCOI2015」小凸玩矩阵 二分答案+二分匹配
#2006. 「SCOI2015」小凸玩矩阵 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- AC日记——「SCOI2015」小凸玩矩阵 LiBreOJ 2006
「SCOI2015」小凸玩矩阵 思路: 二分+最大流: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 300 ...
- loj #2008. 「SCOI2015」小凸想跑步
#2008. 「SCOI2015」小凸想跑步 题目描述 小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏. 操场是个凸 n nn 边形,N NN 个顶点按照逆时针从 0∼n−1 0 ...
随机推荐
- 【剑指Offer】字符串的排列 解题报告(Python)
[剑指Offer]字符串的排列 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://www.nowcoder.com/ta/coding-interviews 题 ...
- RMQ(ST(Sparse Table))(转载)
1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A ...
- C# 编写 Windows 动态桌面软件实现(一)之桌面交互功能
DreamScene2 1.3 版本已经发布了,现在支持鼠标和桌面交互功能.这个功能不会影响性能,基本不占用 CPU.这个功能让我对 Windows 消息机制有了更深入的理解,在这篇博客中我会详细介绍 ...
- 第十六个知识点:描述DSA,Schnorr,RSA-FDH的密钥生成,签名和验证
第十六个知识点:描述DSA,Schnorr,RSA-FDH的密钥生成,签名和验证 这是密码学52件事系列中第16篇,这周我们描述关于DSA,Schnorr和RSA-FDH的密钥生成,签名和验证. 1. ...
- 第二十四个知识点:描述一个二进制m组的滑动窗口指数算法
第二十四个知识点:描述一个二进制m组的滑动窗口指数算法 简单回顾一下我们知道的. 大量的密码学算法的大数是基于指数问题的安全性,例如RSA或者DH算法.因此,现代密码学需要大指数模幂算法的有效实现.我 ...
- JavaScript交互式网页设计 • 【第8章 jQuery动画与特效】
全部章节 >>>> 本章目录 8.1 显示隐藏动画效果 8.1.1 show() 方法与hide() 方法 8.1.2 toggle()方法 8.1.3 实践练习 8.2 ...
- 在页面上绘制一张表格,使用 DOM 节点的动态添加和删除向表格中插入数据,点击表格每行后的“删除”超链接
查看本章节 查看作业目录 需求说明: 在页面上绘制一张表格,使用 DOM 节点的动态添加和删除向表格中插入数据,点击表格每行后的"删除"超链接,使用 DOM 节点的删除操作将对应的 ...
- UML 基本模型元素
目录 1. 结构模型元素 (1)类(class) (2)接口(interface) (3)协作(collaboration) (4)用例(use case) (5)活动类(active class) ...
- SpringCloud集成Security安全(Eureka注册中心)
1.说明 为了保护注册中心的服务安全, 避免恶意服务注册到Eureka, 需要对Eureka Server进行安全保护, 本文基于Spring Security方案, 为Eureka Server增加 ...
- ActiveMQ基础教程(二):安装与配置(单机与集群)
因为本文会用到集群介绍,因此准备了三台虚拟机(当然读者也可以使用一个虚拟机,然后使用不同的端口来模拟实现伪集群): 192.168.209.133 test1 192.168.209.134 test ...