清北学堂-D3-T2-safe

本文介绍了一种将原始O(n^4)复杂度的动态规划问题优化到O(n)的方法。通过预处理最大子段和,利用前缀和技巧,并采用线性时间复杂度更新最优解,实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述
这个题有一个很明显的O(n4)的暴力dp方程,我们考虑优化这个dp:
fi=max(sumisumj+sumksuml)(j<=i,k<=j,l<=k)
后两个sumksuml的值可以通过经典的最大子段和的dp做出来,记为mxj
然后就是这样了:
fi=max(sumisumj+mxj)(j<=i)
提出来sumi
fi=sumi+max(sumj+mxj)(j<=i)
后面那一段可以记录一个变量来O(1)转移,然后时间就是O(n)
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define ll long long
using namespace std;
inline int read(){
    int x=0;char ch=' ';int f=1;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline int lowbit(int x){
    return x&-x;
}
int n;
int a[100001];
int mx[100001];
int mxmx[100001];
int t[100001];
int sum[100001];
int f[100001];
int nm[100001];
int main(){
    freopen("safe.in","r",stdin);
    freopen("safe.out","w",stdout);
    n=read();
    int num=0;
    for(int i=1;i<=n;i++){
        a[i]=read();
        sum[i]=sum[i-1]+a[i];
        num+=a[i];
        if(num>0){
            mx[i]=num;
        }
        else{
            num=0;
        }
    }
    for(int i=1;i<=n;i++){
        if(a[i]<0&&mx[i]==0){
            mx[i]=a[i];
        }
    }
    int now=-0xfffffff;
    for(int i=1;i<=n;i++){
        now=max(now,mx[i]);
        mxmx[i]=now;
    }
    for(int i=1;i<=n;i++){
        nm[i]=mxmx[i]-sum[i];
    }
    now=0;
    int ans=-0xfffffff;
    for(int i=1;i<=n;i++){
        f[i]=sum[i]+now;
        now=max(now,nm[i]);
        ans=max(ans,f[i]);
    }
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值