AcWing 135. 最大子序和


直接把题目化成数学语言,一步一步化简就能做出来了。

假设原序列为a,f为其前缀和(因为涉及区间求和所以用前缀和快)
i∈[1,n]
   ans=max{f[i]-f[i-1],f[i]-f[i-2],...,f[i]-f[i-m]}
   → ans=f[i]-min{f[i-1],f[i-2],...,f[i-m]}

令s[i]=min{f[i-1],f[i-2],...,f[i-m]}
得ans=f[i]-s[i]

根据i∈[1,n]和min{f[i-1],f[i-2],...,f[i-m]}
可以发现这个东西可以有两个理解:
1、滑动窗口求最小值
2、区间最小值(线段树)

滑动窗口代码短而且好写,所以采用第一种理解。
因为滑动窗口处理的时候是i下标的进去一个就进行处理,而s[i]需要的窗口是从i-1开始的,所以对公式进行+1
得到s[i+1]=min{f[i],f[i-1],...,f[i-m+1]},同时i∈[0,n-1]

初始化的时候有地方要注意,假设i==1,那么ans=max{f[1]},并不需要减去什么东西(可以认为是0),包括i==2的时候,ans=max{f[2]-f[1],f[2]},所以要提前push一个0进去,当做第一个窗口未形成时候的减数。

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N=3e5+1;

int n,m,a[N],f[N],s[N],ans=INT_MIN;
deque<pair<int,int>>q;//index,value

int main(){
    for(int i=1 and cin>>n>>m;i<=n and cin>>a[i];++i)f[i]=f[i-1]+a[i];//压行输入

    q.push_back({1,0});
    for(int i=0;i<n;++i){
        while(!q.empty() and f[i]<q.back().second)q.pop_back();
        while(!q.empty() and q.front().first<i-m+1)q.pop_front();
        q.push_back({i,f[i]});
        s[i+1]=q.front().second;
    }

    for(int i=1;i<=n;++i)ans= max(ans,f[i]-s[i]);
    cout<<ans;
    return 0;
}

很明显不卡常数,所以用线段树去求区间极值也是可以过的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值