小兔叽

\(\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」小兔叽的更多相关文章

  1. loj#2009.「SCOI2015」小凸玩密室

    题目链接 loj#2009. 「SCOI2015」小凸玩密室 题解 树高不会很高<=20 点亮灯泡x,点亮x的一个子树,再点亮x另外的子树, 然后回到x的父节点,点亮父节点之后再点亮父节点的其他 ...

  2. 「NOI2013」小 Q 的修炼 解题报告

    「NOI2013」小 Q 的修炼 第一次完整的做出一个提答,花了半个晚上+一个上午+半个下午 总体来说太慢了 对于此题,我认为的难点是观察数据并猜测性质和读入操作 我隔一会就思考这个sb字符串读起来怎 ...

  3. 「SCOI2015」小凸想跑步 解题报告

    「SCOI2015」小凸想跑步 最开始以为和多边形的重心有关,后来发现多边形的重心没啥好玩的性质 实际上你把面积小于的不等式列出来,发现是一次的,那么就可以半平面交了 Code: #include & ...

  4. 「SCOI2015」小凸解密码 解题报告

    「SCOI2015」小凸解密码 题意:给一个环,定义一段连续的极长\(0\)串为\(0\)区间,定义一个位置的离一个\(0\)区间的距离为这个位置离这个区间中\(0\)的距离的最小值,每次询问一个位置 ...

  5. 「SCOI2015」小凸玩矩阵 解题报告

    「SCOI2015」小凸玩矩阵 我好沙茶啊 把点当边连接行和列,在外面二分答案跑图的匹配就行了 我最开始二分方向搞反了,样例没过. 脑袋一抽,这绝壁要费用流,连忙打了个KM 然后wa了,一想这个不是完 ...

  6. 「SCOI2015」小凸玩密室 解题报告

    「SCOI2015」小凸玩密室 虽然有心里在想一些奇奇怪怪的事情的原因,不过还是写太久了.. 不过这个题本身也挺厉害的 注意第一个被点亮的是任意选的,我最开始压根没注意到 \(dp_{i,j}\)代表 ...

  7. LibreOJ #2006. 「SCOI2015」小凸玩矩阵 二分答案+二分匹配

    #2006. 「SCOI2015」小凸玩矩阵 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  8. AC日记——「SCOI2015」小凸玩矩阵 LiBreOJ 2006

    「SCOI2015」小凸玩矩阵 思路: 二分+最大流: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 300 ...

  9. loj #2008. 「SCOI2015」小凸想跑步

    #2008. 「SCOI2015」小凸想跑步   题目描述 小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏. 操场是个凸 n nn 边形,N NN 个顶点按照逆时针从 0∼n−1 0 ...

随机推荐

  1. 【剑指Offer】字符串的排列 解题报告(Python)

    [剑指Offer]字符串的排列 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://www.nowcoder.com/ta/coding-interviews 题 ...

  2. RMQ(ST(Sparse Table))(转载)

    1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A ...

  3. C# 编写 Windows 动态桌面软件实现(一)之桌面交互功能

    DreamScene2 1.3 版本已经发布了,现在支持鼠标和桌面交互功能.这个功能不会影响性能,基本不占用 CPU.这个功能让我对 Windows 消息机制有了更深入的理解,在这篇博客中我会详细介绍 ...

  4. 第十六个知识点:描述DSA,Schnorr,RSA-FDH的密钥生成,签名和验证

    第十六个知识点:描述DSA,Schnorr,RSA-FDH的密钥生成,签名和验证 这是密码学52件事系列中第16篇,这周我们描述关于DSA,Schnorr和RSA-FDH的密钥生成,签名和验证. 1. ...

  5. 第二十四个知识点:描述一个二进制m组的滑动窗口指数算法

    第二十四个知识点:描述一个二进制m组的滑动窗口指数算法 简单回顾一下我们知道的. 大量的密码学算法的大数是基于指数问题的安全性,例如RSA或者DH算法.因此,现代密码学需要大指数模幂算法的有效实现.我 ...

  6. JavaScript交互式网页设计 • 【第8章 jQuery动画与特效】

    全部章节   >>>> 本章目录 8.1 显示隐藏动画效果 8.1.1 show() 方法与hide() 方法 8.1.2 toggle()方法 8.1.3 实践练习 8.2 ...

  7. 在页面上绘制一张表格,使用 DOM 节点的动态添加和删除向表格中插入数据,点击表格每行后的“删除”超链接

    查看本章节 查看作业目录 需求说明: 在页面上绘制一张表格,使用 DOM 节点的动态添加和删除向表格中插入数据,点击表格每行后的"删除"超链接,使用 DOM 节点的删除操作将对应的 ...

  8. UML 基本模型元素

    目录 1. 结构模型元素 (1)类(class) (2)接口(interface) (3)协作(collaboration) (4)用例(use case) (5)活动类(active class) ...

  9. SpringCloud集成Security安全(Eureka注册中心)

    1.说明 为了保护注册中心的服务安全, 避免恶意服务注册到Eureka, 需要对Eureka Server进行安全保护, 本文基于Spring Security方案, 为Eureka Server增加 ...

  10. ActiveMQ基础教程(二):安装与配置(单机与集群)

    因为本文会用到集群介绍,因此准备了三台虚拟机(当然读者也可以使用一个虚拟机,然后使用不同的端口来模拟实现伪集群): 192.168.209.133 test1 192.168.209.134 test ...