双子序列最大和(线性 dp ):最大子段和第 2 弹

99 篇文章 0 订阅

双子序列最大和

题目描述

给定一个长度为 n n n 的整数序列,要求从中选出两个连续子序列,使得这两个连续子序列的序列和之和最大,最终只需输出最大和。一个连续子序列的和为该子序列中所有数之和。每个连续子序列的最小长度为 1 1 1,并且两个连续子序列之间至少间隔一个数。

输入格式

第一行是一个整数表示 n n n

第二行是 n n n 个整数表示整数序列。

输出格式

一个数,两个连续子序列的序列和之和。

样例 #1

样例输入 #1

5
83 223 -13 1331 -935

样例输出 #1

1637

样例 #2

样例输入 #2

3
83 223 -13

样例输出 #2

70

提示

对于 30 % 30\% 30% 的数据 N ≤ 100 N\le 100 N100

对于 60 % 60\% 60% 的数据有 N ≤ 10000 N\le 10000 N10000

对于 100 % 100\% 100% 的数据有 N ≤ 1000000 N\le 1000000 N1000000

数据保证运算过程不会超过 long longint64)。

思路

这道题相比于最大子段和,多了一个子串。那么我们可以类似一个字串来做:

设 f i 为所有以 i 结尾的最大子串和集合( 1 到 i )。 设f_i为所有以i结尾的最大子串和集合(1到i)。 fi为所有以i结尾的最大子串和集合(1i)。
设 g i 为所有以 i 结尾的最大子串和集合( n 到 i )。 设g_i为所有以i结尾的最大子串和集合(n到i)。 gi为所有以i结尾的最大子串和集合(ni)。

  • 其中 f f f 的状态转移为: f i = m a x ( f i − 1 + w i , w i ) f_i=max(f_{i-1}+w_i,w_i) fi=max(fi1+wi,wi) ,这个什么意思呢?就是要么接在上一个串的末尾,要么就另起一个。 g g g 数组的状态转移为: g i = m a x ( g i − 1 + w i , w i ) g_i=max(g_{i-1}+w_i,w_i) gi=max(gi1+wi,wi),这样最后我们在分别 max ⁡ \max max 二者的相邻项,也就是 f i = m a x ( f i − 1 , f i ) f_i=max(f_{i-1},f_i) fi=max(fi1,fi)

这样的话,我们可以对 f i f_i fi 从小到大枚举, g i g_i gi 则从大到小枚举,最后的答案是 m a x ( a n s , f i − 1 + g i + 1 ) max(ans,f_{i-1}+g_{i+1}) max(ans,fi1+gi+1) ,为什么呢?因为题目说中间至少隔着一个。那么本道题的代码就很好写了。

AC 代码

#include<iostream>
#include<cstring>

using namespace std;

const int N = 2e6+10;

int w[N],n;
int f[N],g[N];
int ans=-2e9;

int main(){
    cin>>n;

    memset(f,-0x3f,sizeof f);
    memset(g,-0x3f,sizeof g);

    for(int i=1;i<=n;i++){
        cin>>w[i];
    }

    for(int i=1;i<=n;i++){
        f[i]=max(f[i-1]+w[i],w[i]);
    }

    for(int i=n;i;i--){
        g[i]=max(g[i+1]+w[i],w[i]);
    }

    for(int i=1;i<=n;i++){
        f[i]=max(f[i],f[i-1]);
    }

    for(int i=n;i;i--){
        g[i]=max(g[i],g[i+1]);
    }

    for(int i=2;i<=n;i++){
        ans=max(ans,f[i-1]+g[i+1]);
    }

    cout<<ans;

    return 0;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

green qwq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值