51nod 1254 最大子段和 V2

51nod 1254 最大子段和 V2

原题链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1254
去年做的一个题目。。。那个时候真是抓耳挠腮啊(其实刚接触ACM 也就一年多)
嘻嘻.而且我自己写的我都觉得不好。所以我想再复习一遍。。。

题目有几个点需要注意。首先必须交换。
答案的形式只可能就有三种
交换的两个元素都在答案所在段落内。
或者:
交换的元素都不在答案所在的段落内。
上面两个情况相当于没有交换。
特别的:
第三种就是。把答案所在段落的某个元素与段落外的某个元素交换。
同时。强制交换(必须交换)和 不强制交换 的答案是一样的。
注意:这是因为序列长度不可能小于2.所以我们可以随意浪费一次交换。
根据上面的分析有:
只处理第三种情况和不交换的情况取最大值即为答案。
<script type="math/tex; mode=display" id="MathJax-Element-1"></script>
对于第三种情况。我们把交换看作两种形式。
记:对于第 i 个元素 A[i],用 A[i] 与之前某个元素 A[k] 交换后。得到新的 A[i] .以这个 A[i] 结尾的最大子段和为:
G[i]
为了让 G 的定义更有针对性。(只针对第三种情况)我们尽可能避免掺合不交换的情况。

对于交换后的数列:

A[1],A[2],...,A[k1],A[i],A[k+1],...A[i1],A[k]....

A[i] A[k] 交换后,以新的A[i]结尾的。长度大于1的子段和的最大值。
maxk=1i2(A[k]+maxt=k+1i1(j=ti1A[j]))
长度等于1的:
M[i1]
此时 M[i]=max(A[1],A[2],...A[i])
G[i]=max(maxk=1i2(A[k]+maxt=k+1i1(j=ti1A[j])),M[i1])
其中。 M[i]=max(A[1],A[2],A[3],...A[i])
那么
G[i+1]=max(maxk=1i1(A[k]+maxt=k+1i(j=tiA[j])),M[i])=max(G[i]+A[i],M[i])
其中
G[1]=0
当然这只是处理了一个交换方向。还有从前向后的交换。反向来一次。
G 的最大值不是答案。我们需要把G加上另一侧的贡献的最大值才是答案。
#include <stdio.h>
#include <algorithm>
#define MAXN 50005

using namespace std;
typedef  long long LL;
const int INF=0x3f3f3f3f;
int A[MAXN];
LL Sl[MAXN];
LL Sr[MAXN];

int main ()
{
    int n,i,j;
    LL ans=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++) scanf("%d",A+i);
    for(i=1,j=n;j;i++,j--)
    {
        Sl[i]=Sl[i-1]+A[i];
        Sr[j]=Sr[j+1]+A[j];
        if(Sl[i]<0)Sl[i]=0;
        if(Sr[j]<0)Sr[j]=0;
        if(ans<Sl[i])ans=Sl[i];
    }
    LL maxn=A[1],G=0;
    for(int i=2;i<=n;i++)
    {
        G+=A[i-1];
        if(G<maxn)G=maxn;
        if(ans<G+Sr[i+1])ans=G+Sr[i+1];
        if(maxn<A[i])maxn=A[i];
    }
    G=0;
    maxn=A[n];
    for(int j=n-1;j>0;j--)
    {
        G+=A[j+1];
        if(G<maxn)G=maxn;
        if(ans<G+Sl[j-1])ans=G+Sl[j-1];
        if(maxn<A[j])maxn=A[j];
    }
    printf("%lld\n",ans);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值