题目

在游戏《星际争霸 II》中,高阶圣堂武士作为星灵的重要 AOE 单位,在 游戏的中后期发挥着重要的作用,其技能”灵能风暴“可以消耗大量的灵能对 一片区域内的敌军造成毁灭性的伤害。经常用于对抗人类的生化部队和虫族的 刺蛇飞龙等低血量单位。

你控制着 n 名高阶圣堂武士,方便起见标为 1, 2, · · · , n。每名高阶圣堂武士 需要一定的灵能来战斗,每个人有一个灵能值 ai 表示其拥有的灵能的多少(ai 非负表示这名高阶圣堂武士比在最佳状态下多余了 ai 点灵能,ai 为负则表示这 名高阶圣堂武士还需要 −ai 点灵能才能到达最佳战斗状态)。现在系统赋予了 你的高阶圣堂武士一个能力,传递灵能,每次你可以选择一个 i ∈ [2, n − 1],若 ai ≥ 0 则其两旁的高阶圣堂武士,也就是 i − 1、i + 1 这两名高阶圣堂武士会从 i 这名高阶圣堂武士这里各抽取 ai 点灵能;若 ai < 0 则其两旁的高阶圣堂武士, 也就是 i − 1, i + 1 这两名高阶圣堂武士会给 i 这名高阶圣堂武士 −ai 点灵能。形 式化来讲就是 ai−1+ = ai, ai+1+ = ai, ai− = 2ai。

灵能是非常高效的作战工具,同时也非常危险且不稳定,一位高阶圣堂武士拥有的灵能过多或者过少都不好,定义一组高阶圣堂武士的不稳定度为
maxni=1∣ai∣{max}_{n}^{i=1}|a_i|maxni=1​∣ai​∣ ,请你通过不限次数的传递灵能操作使得你控制的这一组高阶圣堂武 i=1士的不稳定度最小。

输入
本题包含多组询问。输入的第一行包含一个正整数 T 表示询问组数。 接下来依次输入每一组询问。
每组询问的第一行包含一个正整数n,表示高阶圣堂武士的数量。 接下来一行包含n个数a1,a2,··· ,an。
(对于所有评测用例,T ≤ 3,3 ≤ n ≤ 300000,|ai| ≤ 109。)

输出
输出 T 行。每行一个整数依次表示每组询问的答案

样例输入

3
3
5 -2 3
4
0 0 0 0
3
1 2 3

样例输出

3
0
3

解题思路

本题可以DFS列举,但时间肯定会超限。于是,看到一维数列,想到了采用前缀和,对于给定的数列a1—an,其前缀和可以表示为s[1]-s[0]、s[2]-s[1]…s[n]-s[n-1](其中s[0]为0),这样,题目要求的maxni=1∣ai∣{max}_{n}^{i=1}|a_i|maxni=1​∣ai​∣ 就转化为了求前缀和相邻两项之差的最大绝对值的最小值

再来看题目中规定的变换:ai−1+ = ai, ai+1+ = ai, ai−=2ai,反映到前缀和即为:si-1+=ai,si-=ai,因此,如果发生题中所述的变换,即为将原来的si-1和si的值进行交换(使用前缀和之差的好处得以显现,交换操作被简化),而交换并不影响si+1的值。

最后,要求“前缀和相邻两项之差的最大绝对值的最小值”:由于s[0]始终为0不可更改,s[n]又是一个定值,不可交换(因为a[n-1]是最后一个“可选择的高阶圣堂武士”),故本题转变为一个“s[0]、s[n]为定值,s[1]-s[n-1]为已知,通过交换s[1]-s[n-1],使得数组s相邻两个数之间差的绝对值最小的问题”

显然,如果是一个数列a,所有元素都可以自由交换,则升序或者降序排列可使得相邻元素之差绝对值最小;借鉴此思路,我们假设s[0] = min(s[0],s[n]),s[n] = max(s[0],s[n]),那么在s数列的s[0]、s[n]同样可以视为升序数列中的两个点,但原点和终点的位置在数列中间某处,s中的其余数值按照升序排列放入其中,如下图所示:


但我们会发现,原点和终点之间的差值一定会很大,这显然不符合我们要求,所以想到“交叉放置”升序数列中的s[i](i!=0且i!=n)(没有数学推理)。比如,n=9, s[10] = {0,1,-3,2,-6,-1,5,8,-4,4},由于s[0]<s[n],因此选择升序排列,排列后得到{-6,-4,-3,-1,0,1,2,4,5,8}。为了便于直观感受,我画出了最终调换后的数组,如下图所示:

根据实际给定数据的不同,需要注意s[0]和s[n]的大小关系,当前者大于后者时,对s进行降序排列;反之,升序排列。还需要注意最后可能不一定能“跳回”s[n],因此,若恰好无法跳回,注意补充给s[n]赋值。

(参考视频:https://www.bilibili.com/video/BV1Mb411t7M1?share_source=copy_web,感谢分享思路!)

易错点

  1. Lmax函数中,“跳着取”s[i]的值的下标需要注意,以及跳出循环的条件需要注意;
  2. 求出的前缀和可能很大,因此需要以long int来存储,相应的,qsort当中的cmp函数也需要重写,不可以将long int类型直接相减的值作为返回值,否则将排序错误

代码

#include<stdio.h>
#include<stdlib.h>
int cmp_up(const void *a, const void *b){long int c = *(long int *)a;long int d = *(long int *)b;if (c>d)//升序return 1;elsereturn -1;
}int cmp_d(const void *a, const void *b){long int c = *(long int *)a;long int d = *(long int *)b;if (c<d)//降序return 1;elsereturn -1;
}long int int_abs(long int a){//返回long int类型的绝对值return (a>=0)?a:-a;
}long int Lmax(int n, long int s[],int sub_s0, int sub_sn){int i,k=1;long int max=0,temp=0;long int a[n+1];a[0] = 0;//避免0是最小数,a[0]未赋值的情况a[n] = s[sub_sn];//printf("%d %d",sub_s0,sub_sn);for (i=sub_s0-2;i>=0;i-=2)//从s0到s_min/s_max{a[k++] = s[i];if (i<=1)break;}for (i = (i==0)?1:0;i<sub_s0;i+=2)//从s_min到s_0{a[k++] = s[i];if ((i+2)>=sub_s0)break;}for (i = sub_s0+1;i<sub_sn;i++)//中间部分a[k++] = s[i];for (i = sub_sn+1;i<=n;i+=2)//从sn后面的第一个到末尾{a[k++] = s[i];if((i+2)>n)break;}for (i = (i==n)?(n-1):n;i>=sub_sn;i-=2)//从smax回到sn{a[k++] = s[i];if ((i-2)<sub_sn)break;}for (i=1;i<=n;i++)//遍历查找最大值{temp = int_abs(a[i]-a[i-1]);//printf("%ld",temp);if (temp>max)max = temp;}return max;
}int main()
{int T,i,n,j,sub_s0,sub_sn;long int sn;scanf("%d",&T);for (i=0;i<T;i++){scanf("%d",&n);long int a[n+1],s[n+1];//累加和可能是long intsub_s0=-1;sub_sn=-1;s[0] = 0;//为了便于求第一项前缀和for (j=1;j<=n;j++){scanf("%ld",&a[j]);s[j] = s[j-1]+a[j];//求前缀和}sn = s[n];//记录下sn的值,便于之后查找if (sn>=0)//如果sn>s0,那么升序排列qsort(s,n+1,sizeof(long int),cmp_up);else//反之,降序排列qsort(s,n+1,sizeof(long int),cmp_d);for (j=0;j<=n;j++)//sub_sn>sub_s0{if (sub_sn==-1 && s[j]==sn)sub_sn = j;else if (sub_s0==-1 && s[j]==0)sub_s0 = j;if (sub_s0>-1 && sub_sn>-1)//找到了下标break;}printf("%ld\n",Lmax(n,s,sub_s0,sub_sn));}return 0;
}

错误代码

以下代码是错误代码(43分),主要问题是求前缀和的数列没有用long int类型,且Lmax函数中的“跳着取”的边界条件错误。

#include<stdio.h>
#include<stdlib.h>
int cmp_up(const void *a, const void *b){return *(int *)a - *(int *)b;//升序
}int cmp_d(const void *a, const void *b){return *(int *)b - *(int *)a;//降序
}int int_abs(int a){return (a>=0)?a:-a;
}int Lmax(int n, int s[],int sub_s0, int sub_sn){int i,k=1,max=0,temp=0;int a[n+1];a[0] = 0;//避免0是最小数,a[0]未赋值的情况for (i=sub_s0-2;i>1;i-=2)//从s0到s_min/s_maxa[k++] = s[i];for (i = (i==0)?1:0;i<(sub_s0-2);i+=2)//从s_min到s_0a[k++] = s[i];for (i = sub_s0+1;i<sub_sn;i++)//中间部分a[k++] = s[i];for (i = sub_sn+1;i<=(n-2);i+=2)//从sn后面的第一个到末尾a[k++] = s[i];for (i = (i==n)?(n-1):n;i>=(sub_sn+2);i-=2)a[k++] = s[i];a[n] = s[sub_sn];for (i=1;i<=n;i++){temp = int_abs(a[i]-a[i-1]);if (temp>max)max = temp;}return max;
}int main()
{int T,i,n,j,sub_s0,sub_sn;int sn;scanf("%d",&T);for (i=0;i<T;i++){scanf("%d",&n);int a[n+1],s[n+1];sub_s0=-1;sub_sn=-1;s[0] = 0;//为了便于求第一项前缀和for (j=1;j<=n;j++){scanf("%d",&a[j]);s[j] = s[j-1]+a[j];//求前缀和}sn = s[n];//记录下sn的值,便于之后查找if (sn>0)qsort(s,n+1,sizeof(int),cmp_up);elseqsort(s,n+1,sizeof(int),cmp_d);for (j=0;j<=n;j++)//sub_sn>sub_s0{if (sub_sn==-1 && s[j]==sn)sub_sn = j;else if (sub_s0==-1 && s[j]==0)sub_s0 = j;if (sub_s0>-1 && sub_sn>-1)//找到了下标break;}printf("%d\n",Lmax(n,s,sub_s0,sub_sn));}return 0;
}

题目 2307: 蓝桥杯2019年第十届省赛真题-灵能传输相关推荐

  1. 题目 2311: 蓝桥杯2019年第十届省赛真题-Fibonacci 数列与黄金分割

    题目 Fibonacci 数列是非常著名的数列: F[1] = 1,F[2] = 1, 对于 i > 3,F[i] = F[i − 1] + F[i − 2] Fibonacci 数列有一个特殊 ...

  2. [蓝桥杯]2019年第十届省赛真题C/C++ B组 填空+大题

    第十届蓝桥杯省赛题目 填空A:组队 填空B:年号字串 填空C:数列求值 填空 D: 数的分解 填空 E: 迷宫 大题F:特别数的和 大题G:完全二叉树的权值 大题H:等差数列 大题I-后缀表达式 填空 ...

  3. 蓝桥杯2019年第十届国赛真题-大胖子走迷宫

    题目 题目链接 题解 BFS. 整体思路:将位置信息和时刻信息放入队列,根据时刻信息判断当前时刻小明的大小,如果大小为1×11×11×1则不能原地停留,因为没意义啊,停留是为了让自己的肚子减小,但是1 ...

  4. 蓝桥杯题目 2682: 蓝桥杯2022年第十三届省赛真题-GCD

    题目描述 给定两个不同的正整数 a, b,求一个正整数 k 使得 gcd(a + k, b + k) 尽可能大,其中 gcd(a, b) 表示 a 和 b 的最大公约数,如果存在多个 k,请输出所有满 ...

  5. 蓝桥杯2022年第十三届省赛真题-纸张尺寸

    题目描述 在 ISO 国际标准中定义了 A0 纸张的大小为 1189mm × 841mm,将 A0 纸沿长边对折后为 A1 纸,大小为 841mm × 594mm,在对折的过程中长度直接取下整(实际裁 ...

  6. 消除游戏——蓝桥杯2022年第十三届省赛真题

    题目描述 在一个字符串 S 中,如果 S i = S i−1 且S i 不等于S i−1,则称 S i 和 S i+1 为边缘字符.如果S i 不等于S i−1且 S i = S i+1,则 S i− ...

  7. 每日一题——质因数个数(蓝桥杯2022年第十三届省赛真题)

    如何将一个正整数分解质因数:每日一题--将一个正整数分解质因数_笨小古的博客-CSDN博客 题目描述:给定正整数 n,请问有多少个质数是 n 的约数. 输入格式:输入的第一行包含一个整数 n. 输出格 ...

  8. 蓝桥杯2022年第十三届省赛真题-选数异或

    题目描述 给定一个长度为 n 的数列 A1, A2, · · · , An 和一个非负整数 x,给定 m 次查询, 每次询问能否从某个区间 [l,r] 中选择两个数使得他们的异或等于 x . 输入 输 ...

  9. 蓝桥杯嵌入式STM32G431——第七届省赛真题模拟液位检测告警系统

    第七届省赛真题模拟液位检测告警系统 第七届省赛真题 主函数部分的代码功能实现(不包含各模块初始化代码) 第七届省赛真题 主函数部分的代码功能实现(不包含各模块初始化代码) #include " ...

最新文章

  1. 安卓高手之路之 GDI图形引擎篇
  2. 【Java面试题】docker拉取镜像
  3. centos7 网卡配置vlan_Centos7安装后的一些基础配置
  4. Atlas学习手记(9):异步调用Page Method
  5. C#实现渐变颜色的Windows窗体控件
  6. Kmplayer播放器 绿色免安装版 2016 中文版
  7. MIUI V5正式发布 全部功能展示PPT回看
  8. In_interrupt( ) 和In_irq( )【转】
  9. apache tomcat (catalina)查版本(solaris/unix)
  10. php中crypt怎么还原,PHP笔记 —— crypt方法
  11. docker用gpu的参数_初探Docker调用GPU
  12. 阿里云ECS利用密钥对ssh登录服务器
  13. 中国非制式爆炸物薄膜传感器研究取得进展
  14. iOS实现一个简单的视频播放器
  15. 加州大学洛杉机分校计算机科学,加州大学洛杉矶分校计算机科学
  16. 线上服务器老是卡,该如何优化?
  17. loj3059/bzoj5494/洛谷P5294 [HNOI2019]序列 单调栈+主席树
  18. 高中会考计算机都考啥,高中会考都有哪些科目
  19. java多态怎么学_Java学习笔记---多态
  20. matlab多重数值积分,Matlab数值积分和微分(一重、多重都有),简单实用。

热门文章

  1. python yield函数的用法
  2. 教育类自媒体如何运营?自媒体营销的优势主要有哪些方面?
  3. 这所一流大学新规:博士毕不了业,转硕士!
  4. 坚鹏:中国邮储银行金融科技前沿技术发展与应用场景第1期培训
  5. 毕设分享springBoot+vue 中药店商城系统(含源码+论文)
  6. 静电设备在静电处理环节中的原理
  7. Ubuntu安装RabbitMQ
  8. Oracle Patch补丁体系和如何打补丁
  9. LeetCode 面试题 08.11. 硬币 多种解法 完全背包问题
  10. PHPCMS标题设置