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

2023-11-12

题目

在游戏《星际争霸 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。

灵能是非常高效的作战工具,同时也非常危险且不稳定,一位高阶圣堂武士拥有的灵能过多或者过少都不好,定义一组高阶圣堂武士的不稳定度为
m a x n i = 1 ∣ a i ∣ {max}_{n}^{i=1}|a_i| maxni=1ai ,请你通过不限次数的传递灵能操作使得你控制的这一组高阶圣堂武 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),这样,题目要求的 m a x n i = 1 ∣ a i ∣ {max}_{n}^{i=1}|a_i| maxni=1ai 就转化为了求前缀和相邻两项之差的最大绝对值的最小值

再来看题目中规定的变换: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;
    else
        return -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;
    else
        return -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 int
	    sub_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_max
        a[k++] = s[i];
    for (i = (i==0)?1:0;i<(sub_s0-2);i+=2)//从s_min到s_0
        a[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);
	    else
	        qsort(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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • umi+dva+antd后台管理系统(3)---完整登录逻辑

    源码在这儿MyGithub 觉得不错留颗小星星哦 界面准备好啦 开始写登录 1 回顾一下redux是什么 redux 是一个应用数据流框架 主要解决了组件间状态共享的问题 原理是集中式管理 可以让数据更可控 react 中所有数据处理都在
  • JS加减乘除位移方法封装

    常用加减乘除等方法汇总 直接上代码 逻辑简单 代码如下 div 加减乘除位移方法汇总 div
  • 轨迹预处理(轨迹压缩)

    轨迹压缩分为在线压缩和离线压缩两类 在介绍两类压缩算法之前 本文先介绍两种 距离度量 方法 第一种距离度量方法是 垂直的欧几里得距离 如图b所示 p1 p7 p12作为压缩后的点 垂直度量 则为做垂线计算 第二种距离度量方法是 时间同步的欧
  • Dynamics CRM2011 导入解决方案报根组件插入错误的解决方法

    今天在还原一个老版本的解决方案 在导入时报根组件插入问题 Cannot add a Root Component 38974590 9322 e311 b365 00155d810a00 of type 31 because it is n

随机推荐

  • android: ERROR: unknown virtual device nam

    环境变量 ANDROID SDK HOME your path 设置好就没有问题了
  • 刷脸支付服务商为各行各业提供完美体验

    随着刷脸支付技术迭代更新的速度加快 其商业化应用的步伐也越来越快了 4月17日 支付宝推出第二代基于线下消费场景的刷脸支付机具 蜻蜓2 0 定价1499元 同时 新一代蜻蜓还实现了刷脸注册会员卡的功能 切中了苦于获客高成本的线下零售门店的需
  • pve 使用noVNC num lock 不同步的问题

    问题描述 在使用 pve 的noVNC 控制台 访问 WINDOWS 虚拟机时 VM 会出现num lock 状态不同步的情况 主要是由于WINDOWS 笔者这里是 SERVER2022 启动后默认关闭了 num lock 而 pve的虚拟
  • Scala中的抽象类

    1 先看下 类的层次结构 类层次结构 也称为类分类法 是一组相关的类 它们通过继承连接起来做类似的事情 层次结构的顶部可以是一个基类 它下面的所有其他类都是从中派生出来的 或者层次结构可以有多个基类 这些基类的功能稍后会在一个或多个派生类中
  • 论文阅读-Multi-attentional Deepfake Detection

    一 论文信息 题目 Multi attentional Deepfake Detection 作者团队 会议 CVPR 2021 二 背景与创新 背景 之前大多数方法将deepfake检测模型作为一个普通的二分类问题 即首先使用骨干网络提取
  • Redis面试题

    1 基本概念 1 1 常见考点 1 Redis 为何这么快 1 基于内存 2 单线程减少上下文切换 同时保证原子性 3 IO多路复用 4 高级数据结构 如 SDS Hash以及跳表等 2 为何使用单线程 因为 Redis 是基于内存的操作
  • esp32 系列芯片分类

    模组 内置芯片 Flash PSRAM 模组尺寸 mm ESP32 WROVER PCB ESP32 D0WDQ6 4M 8M 18 00 0 10 x 31 40 0 10 x 3 30 0 10 ESP32 WROVER IPEX ES
  • 微信公众号一些错误的原因错误代码41001

    微信公众号一些错误的原因错误代码41001 错误代码41001 缺少access token 碰到这种错误 请检查自己的appid和appsecret posted on 2017 05 08 18 02 baker95935 阅读 评论
  • git如何上传所有的新文件

    目的描述 新建的git项目 项目中有许多要从本地上传到git仓库的新文件 如果用git a filename的方法一个一个的添加 太费事费力 需要有命令添加所有改动 步骤 进入项目文件夹 在其中使用git bash 1 使用git clon
  • MySQL和MongoDB那些事

    什么是 MySQL 和 MongoDB MySQL 和 MongoDB 是两个可用于存储和管理数据的数据库管理系统 MySQL 是一个关系数据库系统 以结构化表格格式存储数据 相比之下 MongoDB 以更灵活的格式将数据存储为 JSON
  • VC++ CSWDirectoryListCtrl磁盘文件列表

    效果图 头文件定义 CSWDirectoryListCtrl h pragma once include afxwin h include
  • leetcode 3. 最长不含重复的子字符串的五种解法

    leetcode链接 最长不含重复的子字符串 题目描述 给定一个字符串 s 请你找出其中不含有重复字符的 最长子串 的长度 示例 1 输入 s abcabcbb 输出 3 解释 因为无重复字符的最长子串是 abc 所以其长度为 3 示例 2
  • Android优化之启动优化和黑白屏优化

    文章目录 一 启动流程 1 开机启动流程 2 app启动流程 二 启动分类 三 黑白屏优化 1 写一个xml文件 activity welcome 2 welcomeActivity类 四 启动优化 1 获取启动时间 2 启动优化方向 一
  • Linux网络配置不生效

    关于解决Linux网络配置文件 修改不生效问题的解决方案 注意 外部问题 例如虚拟网卡 网段及网卡连通问题另行查找相关解决方案 本博客仅介绍比较生僻的Linux系统配置文件不生效有关问题 先看下产生的问题 修改为静态ip却不生效 我们按照正
  • 解决Echarts中双坐标轴分割错位问题

    1 处理函数 Description 刻度最大值 date 2023 08 30 param any isNaN maxValue 1 returns any export const getYAxisMax maxValue number
  • k8s yaml文件

    简介 YAML IPA j m l 尾音类似camel骆驼 是一个可读性高 用来表达资料序列的编程语言 YAML参考了其他多种语言 包括 XML C语言 Python Perl以及电子邮件格式RFC2822 Clark Evans在2001
  • C++基础之初始化、输入输出安全问题及常量问题

    一 C 统一初始化 初始化列表 解决方案 例1 int main int a 10 int b 10 int c 10 初始化列表 int arr 10 1 2 4 5 6 int brr 10 1 2 3 4 5 6 int crr 1
  • GAMES101回顾 -- Geometry

    Geometry Examples of geometry 隐式几何 Inplict 定义 用函数进行表示 如 f x y z 0 显式几何 Explict 定义 所有点都是直接或通过参数映射给出 所有的 u v 映射到对应的 x y z
  • 【毕业设计】爱琴海——基于HTML5的婚庆用品商城网页设计

    一 内容简介 一 背景与意义 婚俗 是指结婚的风俗 各国各族人民按照自己的习俗 举行各具特色的婚礼 具有各自浓厚的民族独特风采 婚俗元素在是中国婚俗文化的媒介 承载了中华儿女对幸福和吉祥的追求 在中国婚俗文化的发展过程中 婚庆用品设计一直在
  • 题目 2307: 蓝桥杯2019年第十届省赛真题-灵能传输

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