ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 P7522 ⎌ Nurture ⎌

2021-04-25 02:04:40  阅读:178  来源: 互联网

标签:P7522 include 题解 累加 leq 答案 Nurture 正数 相反数


题意简述

Link

你有一个长度为 \(n\) 的序列 \(v\),你每次可以 取出 两个数 \(a,b\),并把 \(a-b\) 添加到序列中。重复操作直到序列中只剩下一个数,你需要求出这个数的最大值。

\(1 \leq n \leq 3 \times 10^5 ,0 \leq |v_i| \leq 10^9\) 。

Solution

首先有一个结论,它可能可以帮助您理解下面的式子:因为题目只有减法(有的时候减去一个负数会变成加上一个正数),所以答案 \(\leq \sum_{i=1}^n |v_i|\) 。

然后下文讨论的 \(n\) 都 \(\geq 2\) ,因为 \(n=1\) 的时候不需要操作(当 \(n=1\) 的时候答案是 \(v_1\) ),如果讨论 \(n=1\) 会很麻烦。

首先将 \(v\) 从小到大排序,然后分三种情况讨论:

  1. \(\forall i \in[1,n]v_i\geq 0\)

那么最后一步一定是形如 \(a-b\) 这样的式子。

这个式子最大, \(a\) 应该尽量大, \(b\) 应该尽量小,那么 \(a\) 取 \(v_n\) 就可以了。

至于 \(b\) 的话,它是一堆数相减,因为所有的数都是正数,又要让这个数最小,所以把最小值当做被减数,剩下的全部当做减数(也就是 \(v_1-v_2-v_3\cdots\) ),所以答案就是

\[\begin{aligned} v_n-(v_1-v_2-v_3-\ldots) \\ =v_n-v_1+v_2+v_3+\ldots \\ =-v_1+\sum_{i=2}^n v_i \end{aligned} \]

直接计算即可,复杂度 \(\mathcal{O}(n)\) 。

  1. \(\forall i \in[1,n] v_i \leq 0\)

因为 \(a-(-b)=a+b\) ,而这一部分的所有数字都是负数,所以可以让 \(n-1\) 个数字的相反数(一定是正数)累加到答案里面去,剩下一个数按照原来的值累加到答案里去。

那按照原来的值累加到答案里的那个数字肯定要是最大的(绝对值最小的),剩下的数字一定是变了号。

答案为:

\[v_n-\sum_{i=1}^{n-1} v_i \]

  1. \(v\) 中既有正数,又有负数(也可能有 \(0\) )

首先可以保证的是 \(v_n\) 是正数, \(v_1\) 是负数。

那么可以用 \(v_1\) 减去 \(v_1\sim v_{n-1}\) 中的所有正数都以它的相反数的值累加到 \(v_1\) 中,剩下的 \(v_1\sim v_{n-1}\) 中的数字就全部都是负数了。

再使用 \(v_n\) 逐个把这些数字减去,就能得到最大值了。

这么做之所以是正确的,是因为最后得到的是正数,并且在任何一步操作中,留下来的值的绝对值一定不比原来小、

还有一种方法也可以证明:考虑答案是什么,因为正数都以相反数的值累加到 \(v_1\) 里面去了,而 \(v_1\) 又以它的相反数累加到 \(v_n\) 中了,所以这些正数相当于间接地以它本身值累加到 \(v_n\) 中去了。

对于负数,它直接以它的相反数的值累加到了 \(v_n\) 中。

综上, \(v_i\) 对答案的贡献就是 \(|v_i|\) ,最终答案为:

\[\sum_{i=1}^n |v_i| \]

它与 Solution 开头说的答案最大值是一样的,所以这一定是最优的方法。

几个注意的地方:

  • 记得特判 \(n=1\) 的情况。
  • 记得开 long long

代码如下:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <queue>
typedef long long LL;
using namespace std;
inline int read() {
    int num = 0 ,f = 1; char c = getchar();
    while (!isdigit(c)) f = c == '-' ? -1 : f ,c = getchar();
    while (isdigit(c)) num = (num << 1) + (num << 3) + (c ^ 48) ,c = getchar();
    return num * f;
}
const int N = 3e5 + 5;
int n ,a[N];
signed main() {
    n = read();
    for (int i = 1; i <= n; i++) a[i] = read();
    if (n == 1) {
        printf("%d\n" ,a[1]);
        return 0;
    }
    sort(a + 1 ,a + n + 1);
    if (a[n] <= 0) {
        LL ans = a[n];
        for (int i = 1; i <= n - 1; i++) ans -= a[i];
        printf("%lld\n" ,ans);
    }
    else if (a[1] >= 0) {
        LL ans = -a[1];
        for (int i = 2; i <= n; i++) ans += a[i];
        printf("%lld\n" ,ans);
    }
    else {
        LL ans = 0;
        for (int i = 1; i <= n; i++) ans += a[i] < 0 ? -a[i] : a[i];
        printf("%lld\n" ,ans);
    }
    return 0;
}

好像第一次比赛自己想出这种题(逃

标签:P7522,include,题解,累加,leq,答案,Nurture,正数,相反数
来源: https://www.cnblogs.com/Dragon-Skies/p/14698831.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有