P8684 [蓝桥杯 2019 省 B] 灵能传输 题解

Part 1 提示

  • 题目传送门
  • 欢迎大家指出错误并私信这个蒟蒻
  • 欢迎大家在下方评论区写出自己的疑问(记得 @ 这个蒟蒻)

Part 2 更新日志

  • 2023-06-20 21:46 文章完成
  • 2023-07-03 08:57 文章通过审核
  • 2023-08-21 18:14 更改了文章格式,使文章看起来更加美观

Part 3 背景

这是这个蒟蒻做了将近 \(4\) 天的题目,所以来写篇题解纪念一下。

Part 4 解析

本题涉及到了 \(3\) 种算法:前缀和,排序以及贪心

(1)前缀和

本题实际上要求通过某种灵能传输可以使得该序列的最大值最小。而由前缀和可知,当某一个前缀和序列保持有序(或前缀和序列表示的函数单调)时,其 \(\max(s[i]-s[i-1])\) 的最大值可以达到最小。

通过对几个样例的观察我们不难发现:

1.当 \(a[i]>0\) 时,若 \(a[i-1]=a[i-1]+a[i]\),则 \(s[i-1]\) 等于原来的 \(s[i]\)。

2.若 \(a[i]=a[i]-2a[i]\),则原 \(s[i-1]=s[i-1]+s[i]\)。

3.现 \(s[i]=\) 现 \(s[i-1]-a[i]=\) 原 \(s[i]-a[i]=\) 原 \(s[i-1]\)。

这意味着除了 \(s[0]\) 和 \(s[n]\) 以外,\(1\sim n\) 的任何 \(s[i]\) 都可以进行互相交换,从而得到一个有序序列。而 \(a[i]=s[i]-s[i-1]\) 也就意味着可以通过交换 \(s[i]\) 的方式得到灵能传输后的最终结果。

(2)排序

for (int i = 1; i <= n; i++) {
scanf("%d", &a[i], s[i] = s[i - 1] + a[i]);
}
sort(s + 1, s + 1 + n);

当然,如果 \(s[0]\) 和 \(s[n]\) 也可以正常交换,则只需要将整个前缀和序列进行排序,即可直接得到一个单调函数,那么本题的推导到这一步就可以结束了,可以通过直接计算 \(\max(s[i]-s[i-1])\) 的值获得最大值和最小值。但问题就在于 \(s[0]\) 和 \(s[n]\),即最终得到的序列不一定是单调的,所以接下来就要通过一系列操作解决序列不单调的问题。

(3)贪心

通过上述的分析可以得知,想要求出本题的最优解就是使得所求序列尽可能保持单调。通过画图可知,在两个端点无法移动的条件下,在对于整个前缀和序列进行排序时,总能得到一个拥有两个拐点且中间部分保持单调的函数。此时就应该往贪心上思考,即当一条有两个拐点的曲线的重叠部分最小时单调部分最多,而一条曲线符合下列情况时符合要求。

①左端点小于右端点,即 \(s[0]<s[n]\)。在记录 \(s_0\) 和 \(s_n\) 的值时需要进行一次判定,如果得到的左端点比右端点大,那么就将这两个端点交换(尽量保证得到的函数是一个中部递增的单调函数,其目的是将得到的所有函数都变成中部递增函数,这样就可以少算至少一半的数据)。

if (s0 > sn) {
swap(s0, sn);
}

②极小值在极大值左边(刚刚的情况中,要求得到的函数一定是中部递增的,因此不仅需要控制函数中部的递增,还要控制最大值和最小值以使得中部函数递增)。这就要求在后续选点时应遵循 \(s[0]\) 向左取,\(s[n]\) 向右取,因为这样才能取得两边的极值。

因为已经将两个端点确定并保证了两者的顺序,也对前缀和序列进行了升序处理,于是此时得到了一个存放着递增的前缀和序列的有序数组(左右端点的位置已经发生改变,情况①中已经记录了两者位置)。

接下来需要从左端点的位置向左依次取点,从右端点的位置向右依次取点(从左端点向左依次取点并取得前缀和序列的最小值,从右端点向右依次取点并取得前缀和序列的最大值)。此时通过画图可以求得函数为两个端点有拐点且中部有序递增的函数。

int l = 0, r = n - 1;
for (int i = s0; i >= n; i -= 2) {
f[l++] = s[i];
st[i] = true;
}
for (int i = sn; i <= n; i += 2) {
f[r--] = s[i];
st[i] = true;
}
for (int i = 0; i <= n; i++) {
if (st[i] == false) {
f[l++] = s[i];
}
}

因为图像中有两个拐点而且会形成两个重叠部分,所以想要得到最优解,就要使得求得的函数图像中的递增部分尽可能地多,这样拐点处的图像就会尽可能地少,即可保证序列 \(f\) 为重叠部分最小的前缀和序列。

在通过特定规则将所有点都遍历完毕后,此时已经得到最优解的图像(前缀和序列)。最后就是求出所有前缀和表示的灵能值中的最大者(一定为正),该灵能值便是最终答案。

int res = 0;
for (int i = 1; i <= n; i++) {
res = max(res, abs(f[i] - f[i - 1]));
}

\(res\) 即为所求结果。

Part 5 代码

#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
typedef long long ll;
ll a[N];
ll s[N];
ll f[N];
bool st[N];
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
s[0] = 0;
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
s[i] = s[i - 1] + a[i];
}
ll s0 = s[0];
ll sn = s[n];
if (s0 > sn) {
swap(s0, sn);
}
sort(s, s + 1 + n);
for (int i = 0; i <= n; i++) {
if (s0 == s[i]) {
s0 = i;
break;
}
}
for (int i = 0; i <= n; i++) {
if (sn == s[i]) {
sn = i;
break;
}
}
memset(st, false, sizeof st);
int l = 0, r = n;
for (int i = s0; i >= 0; i -= 2) {
f[l++] = s[i];
st[i] = true;
}
for (int i = sn; i <= n; i += 2) {
f[r--] = s[i];
st[i] = true;
}
for (int i = 0; i <= n; i++) {
if (st[i] == false) {
f[l++] = s[i];
}
}
ll res = 0;
for (int i = 1; i <= n; i++) {
res = max(res, abs(f[i] - f[i - 1]));
}
printf("%lld\n", res);
}
return 0;
}

P8684 [蓝桥杯 2019 省 B] 灵能传输 题解的更多相关文章

  1. 第十届蓝桥杯2019年C/C++ 大学B组省赛试题

    2019年第十届蓝桥杯大赛软件类省赛C/C++大学B组 试题 A:组队 本题总分:5分 [问题描述] 作为篮球队教练,你需要从以下名单中选出 1号位至 5号位各一名球员, 组成球队的首发阵容. 每位球 ...

  2. 第十届蓝桥杯2019年C/C++ 大学A组省赛试题

    2019年蓝桥杯第十届软件类省赛 C/C++ 大 学 A 组 试题 A: 平方和 本题总分:5 分 [问题描述] 小明对数位中含有 2.0.1.9 的数字很感兴趣,在 1 到 40 中这样的数包括 1 ...

  3. 【备考06组01号】第四届蓝桥杯JAVA组A组国赛题解

    1.填算式 (1)题目描述     请看下面的算式:     (ABCD - EFGH) * XY = 900     每个字母代表一个0~9的数字,不同字母代表不同数字,首位不能为0.     比如 ...

  4. 2019年第十届蓝桥杯c++A组java/c++组题解

    #include<iostream> #include<vector> using namespace std; vector <int > vec; long l ...

  5. 今日学习——蓝桥杯 2019年 C语言 B组

    1.手淦(亲身体验,,,没啥大用,最终还是代码) 2.代码(下面是我看其他博主代码答案能看的懂的....具体的可以直接去下面的网址看) https://blog.csdn.net/qq_4452491 ...

  6. 2019 蓝桥杯国赛 B 组模拟赛 题解

    标签 ok #include<bits/stdc++.h> using namespace std; /* 求阶乘 去除尾部0 每次求阶乘时:结果去除尾0,并对 1e6取余 */ type ...

  7. 蓝桥杯2019初赛]迷宫(dfs版本)

    传送门 大意: 题目的意思还是模板的搜索,不同的是我们要记录路径了,而且是最短字典序最小的路径. 思路: 1.对于字典序最小,也就是说我们要尽量先往下走,然后是左- 这个很简单,因为在dfs中是顺序枚 ...

  8. P8701 [蓝桥杯 2019 国 B] 第八大奇迹

    简要题意 你需要维护一个长度为 \(L\) 的序列 \(a\),初始时全部都是 \(0\),有 \(N\) 个操作,支持: C p x,将 \(a_p\) 修改为 \(x\). Q a b,输出 \( ...

  9. 2015年蓝桥杯B组C/C++决赛题目

    2015年第六届蓝桥杯B组C/C++国赛题目 点击查看2015年第六届蓝桥杯B组C/C++国赛题解     1.积分之迷 小明开了个网上商店,卖风铃.共有3个品牌:A,B,C. 为了促销,每件商品都会 ...

  10. 2018年蓝桥杯B组C/C++决赛题目

    自己的博客排版,自我感觉略好一点. 先放上题目. 点击查看2018年蓝桥杯B组C/C++决赛题目题解     1.换零钞 x星球的钞票的面额只有:100元,5元,2元,1元,共4种. 小明去x星旅游, ...

随机推荐

  1. WPF入门教程系列二十九 ——DataGrid使用示例MVVM模式(7)

    WPF入门教程系列目录 WPF入门教程系列二--Application介绍 WPF入门教程系列三--Application介绍(续) WPF入门教程系列四--Dispatcher介绍 WPF入门教程系 ...

  2. WakaTime Readme Stats-开源项目翻译

    寻找不同语言和地区的翻译 #23 Readme中添加了功能标志的开发指标 眼前一亮的Readme统计数据 你是早起的还是夜间的? 你一天中什么时候工作效率最高? 你用什么语言编写代码? 让我们在你的个 ...

  3. LEA: Improving Sentence Similarity Robustness to Typos Using Lexical Attention Bias 论文阅读

    LEA: Improving Sentence Similarity Robustness to Typos Using Lexical Attention Bias 论文阅读 KDD 2023 原文 ...

  4. 2023-07-19:布尔表达式 是计算结果不是 true 就是 false 的表达式 有效的表达式需遵循以下约定: ‘t‘,运算结果为 true ‘f‘,运算结果为 false ‘!(subExpr

    2023-07-19:布尔表达式 是计算结果不是 true 就是 false 的表达式 有效的表达式需遵循以下约定: 't',运算结果为 true 'f',运算结果为 false '!(subExpr ...

  5. ranger2.1.0源码编译以及安装

    ranger2.1.0源码编译以及安装 编译环境准备 环境需求 示例版本 JDK8 Java(TM) SE Runtime Environment (build 1.8.0_231-b11) mave ...

  6. Git:多人写作时,如何保证代码一致性

    解决方案 git add . git commit -m "message" git pull origin develop # 拉取并合并dev分支上的代码 git push

  7. UE源码分析:Slate 类鼠标输入处理

    序言 UE4.25版本 本章看一下UE的 "类鼠标"输入处理(其实就是鼠标和触摸的输入,我也没找到专门的术语来代指,英文UE用的是PointerXXX),主要是按下.移动.抬起等相 ...

  8. Hi3798MV200 恩兔N2 NS-1 (三): 制作 Ubuntu rootfs

    目录 Hi3798MV200 恩兔N2 NS-1 (一): 设备介绍和刷机说明 Hi3798MV200 恩兔N2 NS-1 (二): HiNAS海纳思使用和修改 Hi3798MV200 恩兔N2 NS ...

  9. 使用kubeadm部署kubernetes

    k8s版本:1.15.0 前期准备 节点: master:172.50.13.103(2核2G) node-1:172.50.13.104(2核2G) node-2:172.50.13.105(2核2 ...

  10. Unity的AssetPostprocessor之Model:深入解析与实用案例 1

    Unity AssetPostprocessor模型相关函数详解 在Unity中,AssetPostprocessor是一个非常有用的工具,它可以在导入资源时自动执行一些操作.在本文中,我们将重点介绍 ...