51nod 1052[最大子段和]【DP】

28 篇文章 0 订阅
9 篇文章 0 订阅

Description

N个整数组成的序列a[1],a[2],a[3],…,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的。如果M >= N个数中正数的个数,那么输出所有正数的和。

例如:-2 11 -4 13 -5 6 -2,分为2段,11 -4 13一段,6一段,和为26。

题解

首先,题目的意思有点绕,这里的答案其实是可以选 1..m 个子段的最优解。

那么,我们定义 f[i][j] 表示第 i 位,当前总共选了j段的最优解,那么有转移方程 f[i][j]=max(f[i1][j]+a[i],f[k][j1]+a[i]) ,这里的 k 是所有[1,i1]的数,这样,我们就得到了一个 N3 的算法,优化到 N2 只要开一个 g[i] 表示所有 f[k][i] 的最大值就可以。最后由于空间限制比较毒,所以还要开滚动数组。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 5006
#define LL long long
using namespace std;
inline char nc(){
    static char buf[100000],*i=buf,*j=buf;
    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
    char ch=nc();int sum=0,p=1;
    while(ch!='-'&&!(ch>='0'&&ch<='9'))ch=nc();
    if(ch=='-')p=-1,ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum*p;
}
int n,m,a[maxn];
LL ans,sum[maxn],g[maxn],f[2][maxn];
int main(){
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    n=_read();m=_read();
    for(int i=1;i<=n;i++)a[i]=_read();
    memset(f,192,sizeof(f));memset(g,192,sizeof(g));
    g[0]=0;
    for(int i=1;i<=n;i++)
     for(int j=m;j>=1;j--){
        f[i&1][j]=max(g[j-1]+a[i],f[1-(i&1)][j]+a[i]);
        g[j]=max(g[j],f[i&1][j]);
        ans=max(ans,f[i&1][j]);
     }
    printf("%lld",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值