C/C++百题打卡[4/100]——融合最大数


⌛️



Math ☁️

上一题链接: C/C++百题打卡[3/100]——约瑟夫问题⭐️⭐️⭐️.
下一题链接: C/C++百题打卡[5/100]——合唱队形 [考查 数组 ]⭐️⭐️⭐️⭐️.
百题打卡总目录: 🚧 🚧 …


一、题目总述

● 有一个初始长度为 n n n 的序列 a a a。你需要进行 n − 1 n-1 n1 次操作。每一次操作前先在当前序列中选出两个相邻的数 x , y x,y x,y 并删除(原序列中 x x x y y y 左边),再往原位置插入一个数值为 x + y x+y x+y 或一个 x − y x−y xy 的数。 n − 1 n−1 n1 次操作之后最终只会剩下恰好一个数,求这个剩下的数的最大值

输入描述
第一行,一个整数 n n n
第二行,共 n n n 个整数 a i a_i ai,( i = 1 , 2 , . . . , n i=1,2,...,n i=1,2,...,n)

输出描述
共一行,一个整数,表示答案。

注意:对于 100 100% 100 的数据, 1 ≤ n ≤ 1 0 5 , ∣ a i ∣ ≤ 1 0 9 1 ≤ n ≤ 10 1\le n\le 10^5 ,|a_i|\le 10^91≤n≤10 1n105,ai1091n10 ,运行限制——>最大运行时间: 1 s 1s 1s,最大运行内存: 128 M 128M 128M

输入样例

5
-1 1 1 -1 1 

输出样例

3

样例解释【一种操作过程如下:】

-1 1 1 -1 1
-1 1 1 -2
-1 1 3
-1 4
3

可以证明没有更优的方案。



二、思考空白区






题目难度:⭐️⭐️

建议思考时间:⌛️ ⌛️








三、题目解析

● 这是一道考查数学推导的题。可以益智大脑。

● 主要就是要做到 “认真分析题目 + 数学的证明 ”。

  • 这里,我采用数学归纳法来解析这道题。(好像是叫这种方法吧,叫数学推导法也行,也就是一步步推导过来的)
    ① 首先,如果n=1,只有一个数字,那么直接输出就行了。
    ② 如果n=2,且不管 a 1 a_1 a1 的正负,若 a 2 ≥ 0 a_2≥0 a20,那么 a 1 + a 2 a_1+a_2 a1+a2 就是最大数。
    ③ 如果n=2,且不管 a 1 a_1 a1 的正负,若 a 2 < 0 a_2<0 a2<0,那么 a 1 − a 2 a_1- a_2 a1a2 就是最大数。

● 以上就是基础推导部分,也容易理解。

● 但当 n ≥ 3 n≥3 n3 时,比如对于序列 “ a 1 、 a 2 、 a 3 a_1、a_2、a_3 a1a2a3 ” 来说,是先执行 “ a 1 与 a 2 a_1与a_2 a1a2 的加法/减法 ”,还是先执行 “ a 2 与 a 3 a_2与a_3 a2a3 的加法/减法 ” 呢?

● 如果你这么想,那么问题就复杂了,你想想,要是n>10000的话,那不得考虑得好复杂。

  • 所以,我们需要转换一下思维。只需要想通下面这一点,那么这道题就迎刃而解了。
    [1] 如果我们有一个长度n>3的序列 a 1 、 a 2 、 a 3 、 . . . 、 a n a_1、a_2、a_3、...、a_n a1a2a3...an,我们一定可以人为地把它们划分成两
    [2] 一堆是 { a 1 、 a 2 、 a 3 、 . . . 、 a n − 1 } \{a_1、a_2、a_3、...、a_{n-1} \} {a1a2a3...an1},另一堆是 { a n } \{a_n \} {an}
    [3] 很显然,前面一堆通过计算最终会得到一个数,它和后面一堆里面的 a n a_n an 刚好就形成了前面基础推导部分的 ②③ 中的一个。那么就确定了 a n a_n an 前面的符号(+或者-)
    [4] 同理,我们也可以继续对 { a 1 、 a 2 、 a 3 、 . . . 、 a n − 1 } \{a_1、a_2、a_3、...、a_{n-1} \} {a1a2a3...an1} 进行拆分,拆分成 { a 1 、 a 2 、 . . . 、 a n − 2 } \{a_1、a_2、...、a_{n-2} \} {a1a2...an2} { a n − 1 } \{a_{n-1} \} {an1} 然后操作步骤就同理 [3] 了。也就确定了 { a n − 1 } \{a_{n-1} \} {an1} 前面的符号(+或者-)
    [5] 最后依次类推即可。

● 此时,问题就简化为:只要是负数,对它进行 “减操作”;只要是非负数,对它进行 “加操作” 即可得到最后的最大数。



四、完整代码(C和C++版)

  ● C 语言版本:【边输入,就边在计算最终结果】

#include<stdio.h>
int main()
{
    int n, x;
    long long int ans = 0;	// 一定要开得足够大
    scanf("%d", &n);
    scanf("%d", &x);	// 读取第一个数
    ans = x;    		// 答案赋初始值 
    for (int i = 1; i < n; i++)
    {
        scanf("%d", &x);		// 读取后续的数字,并做后续从处理, 实时更新答案
        if (x < 0)				// 是负数就减
        {
            ans -= x;
        }
        else					// 是正数就加
        {
            ans += x;
        }
    }
    cout << ans;
    return 0;
}

  ● 补充说明int 默认是占4个字节,数值表示范围是:-2147483648 ~ 2147483647,大约21亿。在大多情况下int类型都是可以满足需要的,但不乏有特殊情况【比如这道题】,这时就要用到long long int类型了,其取值范围是:-9223372036854775808 ~ 9223372036854775807。这个数值范围还是很大,它在内存中占用8个字节。

  ● 运行结果:

在这里插入图片描述


  ● C++ 版本:

#include<iostream>
using namespace std;
int main()
{
    int n, x;
    long long int ans = 0;
    cin >> n;
    cin >> x;	// 读取第一个数
    ans = x;    // 答案赋初始值 
    for (int i = 1; i < n; i++)
    {
        cin >> x;		// 读取第二个数,并做后续从处理, 实时更新答案
        if (x < 0)		// 是负数就减
        {
            ans -= x;
        }
        else			// 是正数就加
        {
            ans += x;
        }
    }
    cout << ans;
    return 0;
}


五、做题小结与反思

  ● 一般很复杂的数学问题,只要从最开始,最简单的情况开始分析,然后把后面复杂的情况尽可能地归化到最简单的情况即可。



六、参考附录

[1] 原题地址:https://www.luogu.com.cn/problem/P7917.

上一题链接: C/C++百题打卡[3/100]——约瑟夫问题⭐️⭐️⭐️.
下一题链接: C/C++百题打卡[5/100]——合唱队形 [考查 数组 ]⭐️⭐️⭐️⭐️.

百题打卡总目录: 🚧 🚧 …


C/C++百题打卡[4/100]——融合最大数 [题目源自 洛谷 ] ⭐️⭐️
标签:数学

因为最近有重要考试所以缓更一周
   2021/12/12     

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一支王同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值