“前缀和 + 全局偏移量 + 二分查找” 预处理 --> 求解”最大子序列和“题型

B3799 [NICA #1] 序列 - 洛谷

初始代码无法AC:

        原因存在多次遍历的情况容易超时

import sys

def add_k(nums, k):
    for w in range(len(nums)):
        nums[w] += k
    return nums

def max_subsequence_sum(nums):
    if not nums:
        return False
    sum_ = sum(i for i in nums if i > 0)

    if sum_ > 0:
        return sum_
    
    else:
        return max(nums)

def select_operation(nums,operations):
    res = []
    for op in operations:
        if len(op) > 1:
            add_k(nums,op[1])
        else:
            max_subsequence_sum(nums)
            res.append(max_subsequence_sum(nums))
            # 删除 --> nums[:] = original # 不用于nums = original 前者实际修改里面的内容,后者修改引用

    return res

n,m = map(int, sys.stdin.readline().split())
nums = list(map(int, sys.stdin.readline().split()))
operations = list(tuple(map(int, sys.stdin.readline().split())) for _ in range(m))
print("\n".join(map(str, select_operation(nums,operations))))

优化代码:

import sys
from itertools import accumulate

def main():
    data = sys.stdin.read().split()
    iter_ = iter(data)  # 输入数据转换为迭代器
    n = int(next(iter_))
    m = int(next(iter_))

    # 读取原始数组
    arr = [int(next(iter_))for _ in range(n)]
    arr.sort(reverse=True)
    pre = [0] + list(accumulate(arr)) # 预处理数组为”前缀和数组“
    # 写[0] --- 表示当前求解最大子序列和,可以取空集

    k_count = 0 # 全局偏移变量k
    ans = [] # 存放输出答案

    # 在允许操作数内进行操作
    for _ in range(m):
        op = int(next(iter_))
        if op == 1:
           k = int(next(iter_))
           k_count += k

        elif op == 2:
            left, right = 0, n-1 
            while left < right: 
                mid = left + (right - left + 1) // 2 # 右偏!!找到最后一个 +k_count > 0 的位置)
                if arr[mid] + k_count > 0:
                    left = mid  # mid位置满足条件,[0 ~ (mid-1)]也一定可以满足,继续向后找,令序列尽可能长
                else: 
                    right = mid - 1    
            
            count = left + 1 # 索引 = 满足条件的数量, 补充了一个空集[0]的位置
            
            '''
            low, high = 0, n-1
            while low < high: # 找到第一个+k_count < 0 的位置
                mid = low + (high - low) // 2  # 不需要右偏
                if arr[mid] + k_count < 0:
                    high = mid
                else:
                    low = mid + 1
            count = high  # 元素数量,对应上prefix[]中的索引位置,不然是要-1的(没有空集【】的话)
            
            '''
            if count > 0: # 满足条件的数量至少为1个
                sum_ = pre[count] + k_count*count
            else: # 全为负数,不取任何元素 --- 空集
                sum_ = 0
            ans.append(str(sum_))
    sys.stdout.write("\n".join(ans))


if __name__ == "__main__":
    main()

'''
5 5
-5 12 -7 2 8
2
1 3
2
1 4
2

'''

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值