4414 子序列(分类讨论、贪心)

1. 问题描述:

给定一个长度为 n 的整数序列 a1,a2,…,an,请你找到一个该序列的子序列,要求:

  1. 该子序列的所有元素之和必须是奇数。
  2. 在满足条件 1 的前提下,该子序列的所有元素之和应尽可能大。

输出你找到的满足条件的子序列的所有元素之和。保证至少存在一个满足条件的子序列。注意,子序列不一定连续。

输入格式

第一行包含一个整数 n。第二行包含 n 个整数 a1,a2,…,an。

输出格式

输出一个整数,表示满足条件的子序列的所有元素之和。

数据范围

前 6 个测试点满足 1 ≤ n ≤ 5
所有测试点满足 1 ≤ n ≤ 10 ^ 5,−10 ^ 4 ≤ ai ≤ 10 ^ 4

输入样例1:

4
-2 2 -3 1

输出样例1:

3

输入样例2:

3
2 -5 -3

输出样例2:

-1
来源:https://www.acwing.com/problem/content/description/4417/

2. 思路分析:

分析题目可以知道第二个条件比较好处理所以我们可以先考虑第二个条件,因为需要使得和最大所以可以使用一个变量 s 来记录 a 中所有大于 0 的元素之和,如果 s 恰好为奇数那么很好满足了第一个条件所以当前的 s 就是答案,如果为偶数那么不满足第一个条件,所以问题的关键是当 s 为偶数的时候如何处理,当 s 为偶数的时候那么 s 肯定是由偶数个正奇数组成,要想使得 s 为奇数那么分为两种情况(奇偶性只需要看正奇数的个数即可):第一种情况是 s 减去一个已经加上的最小的正奇数,第二种情况是加上一个最大的负奇数这样才可以使得 s 是最大的,加上和减去一个负数都可以使得 s 由偶数变为奇数,两种情况取一个 max 就是答案,我们可以在遍历数组 a 的时候使用 odd_pos 和 odd_even 来记录正的奇数和负的奇数,最后对 odd_pos 从小到大排序,odd_even 从大到小排序,在两种情况取一个 max 就是答案。

3. 代码如下:

python:

class Solution:
    def process(self):
        n = int(input())
        a = list(map(int, input().split()))
        s = 0
        INF = 10 ** 10
        # odd_pos和odd_neg记录正的奇数和负的奇数
        odd_pos, odd_neg = list(), list()
        for x in a:
            if x & 1:
                # x & 1 == 1 表示 x 是奇数否则为偶数
                if x > 0:
                    odd_pos.append(x)
                else:
                    odd_neg.append(x)
            if x > 0:
                s += x
        # 说明当前所有正数之和为奇数所以当前的s为最大
        if s & 1:
            print(s)
        else:
            # 考虑去掉一个正的奇数或者加上一个负的奇数这两种情况, 两种情况取一个max就是答案
            odd_pos.sort()
            odd_neg.sort(reverse=True)
            res = -INF
            if len(odd_pos):
                res = s - odd_pos[0]
            if len(odd_neg):
                res = max(res, s + odd_neg[0])
            print(res)


if __name__ == '__main__':
    Solution().process()

我们只关心最大的负奇数和最小的正奇数,所以使用两个变量odd_pos 和 odd_neg 来维护即可,这样可以不用存储所有的正奇数和负奇数,省略了排序的步骤:

class Solution:
    def process(self):
        n = int(input())
        a = list(map(int, input().split()))
        s = 0
        INF = 10 ** 10
        odd_pos, odd_neg = INF, -INF
        for x in a:
            if x & 1:
                if x > 0:
                    odd_pos = min(odd_pos, x)
                elif x < 0:
                    odd_neg = max(odd_neg, x)
            if x > 0:
                s += x
        if s & 1:
            print(s)
        else:
            res = -INF
            if odd_pos != INF:
                res = s - odd_pos
            if odd_neg != -INF:
                res = max(res, s + odd_neg)
            print(res)


if __name__ == '__main__':
    Solution().process()

go:

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"sort"
)

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func run(r io.Reader, w io.Writer) {
	in := bufio.NewReader(r)
	out := bufio.NewWriter(w)
	defer out.Flush()
	var n, x int
	fmt.Fscan(in, &n)
	var odd_pos, odd_neg []int
	s := 0
	for i := 0; i < n; i++ {
		fmt.Fscan(in, &x)
		if x&1 == 1 {
			if x > 0 {
				odd_pos = append(odd_pos, x)
			} else {
				odd_neg = append(odd_neg, x)
			}
		}
		if x > 0 {
			s += x
		}
	}
	INF := 10000000000
	if s&1 == 1 {
		fmt.Fprintln(out, s)
	} else {
		res := -INF
		sort.Ints(odd_pos)
		sort.Sort(sort.Reverse(sort.IntSlice(odd_neg)))
		if len(odd_pos) > 0 {
			res = s - odd_pos[0]
		}
		if len(odd_neg) > 0 {
			res = max(res, s+odd_neg[0])
		}
		fmt.Fprintln(out, res)
	}
}

func main() {
	run(os.Stdin, os.Stdout)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值