算法之AcWing 3493. 最大的和---Python3

6 篇文章 0 订阅
3 篇文章 0 订阅

题目

在这里插入图片描述

输入样例和输出样例

在这里插入图片描述
分析输入,n为数列的长度,也即数据的个数;k为选取的区间,也即可选状态; a i a_i ai为具体数据的内容。每个数据对应一个状态,0或者1,如果数据在区间里面,可以从0变到1。

代码实现

#AcWing 3493. 最大的和
# 滑动指针,不用开数组记录前缀和
# 思路 求和:ans:标签为1的和+delta_res:改变标签为1的和

# 求标签为1的和
def sum_1(arr, bos):
    ans = 0  # 求和,求标签为1的和
    for a, b in zip(arr, bos):  # 打包为元组的列表,元素个数与最短的列表一致
        ans = ans + a * b
    return ans


# 求前k个区间的标签为0的和,和下面进行对比,选取最大值
def delta_k(k):
    delta = 0
    for i in range(k):
        delta = delta + arr[i] * (1 - bos[i])
    #delta_res = delta
    return delta


# k区间,改变标签为1的和,比较,选取最大值
def delta_change(arr,k):
    delta_res,delta=delta_k(k),delta_k(k)
    l, r = 0, k
    while r < n:  # k小于n,区间长度小于数字长度
        #delta=0 #归零
        inc = arr[r] * (1 - bos[r]) - arr[l] * (1 - bos[l])
        #print("inc:",inc)
        delta = delta + inc
        l = l + 1
        r = r + 1
        if inc > 0:
            delta_res = max(delta_res, delta)
       # elif delta_res ==0:  #处理前k区间刚好是最大的情况
            #delta_res = delta_k(k)
    return delta_res


if __name__ == "__main__":
    # 输入
    n, k = map(int, input().split())  # n为数组长度,k为选取区间长度
    arr = list(map(int, input().split()))  # n个数,存储在arr中
    bos = list(map(int, input().split()))  # 1 or 0 ,可以考虑用字典储存
    # 输出
   # print("1:",sum_1(arr,bos))
    #print("2:",delta_change(arr,k))
   #print("3:",delta_k(k))
    print(sum_1(arr,bos) + delta_change(arr,k))

代码待优化

其他参考代码

n, k = map(int, input().split())
nums = list(map(int, input().split())) # 原数组
freq = list(map(int, input().split()))  # 初始可选状态数组
s = 0  # 当前滑动窗口内初始不可选的数字总和
cnt = 0  # 滑动窗口内初始不可选的数字总和的历史最大值
opt = 0  # 原数组内初始可选数字的总和

left, right = 0, 0  # 滑动窗口左右边界
while right < n:
    if freq[right] == 1:  # 判断右边界的数字初始是否可选
        opt += nums[right]
    else:
        s += nums[right]
    if right - left + 1 >= k:  # 窗口滑动
        cnt = max(cnt, s)
        if freq[left] == 0:  # 移动左侧窗口
            s -= nums[left]
        left += 1
    right += 1
print(cnt + opt)


n,k=map(int,input().split())
arr=list(map(int,input().split()))
bin=list(map(int,input().split()))

S=0
# 累加状态为1的数
for i in range(n):
    if bin[i]:
        S+=arr[i]

res=0
pre=0
# 滑动窗口计算长度为k的区间状态为0对应数值的和
for i in range(n):
    if bin[i]==0:
        pre+=arr[i]
    res=max(res,pre+S)
    if i>=k-1 and bin[i-k+1]==0:
        pre-=arr[i-k+1]

print(res)

作者:追风少年666
链接:https://www.acwing.com/activity/content/code/content/1222584/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

C代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010;

int n, m;
int a[N], b[N];

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    for (int i = 0; i < n; i ++ ) scanf("%d", &b[i]);

    LL sum = 0;
    for (int i = 0; i < n; i ++ )
        if (b[i])
            sum += a[i];

    LL v = 0, s = 0;
    for (int i = 0; i < n; i ++ )
    {
        if (!b[i]) s += a[i];
        if (i >= m && !b[i - m]) s -= a[i - m];
        v = max(v, s);
    }

    printf("%lld\n", sum + v);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值