HDU1024 Max Sum Plus Plus 【区间dp】【滚动数组】

HDU1024 Max Sum Plus Plus

题意:给你一个N个元素的数列,你需要从中选M个区间,区间之间不能有交叉,问选取的M个区间之和最大值是多少? (N是1e6的数量级)

分析

我们考虑一个数一个数的放,过程是怎么样的。如果当前是选取第i个区间,现在要尝试放入a[j],那么就会出现两种情况:
1.a[j]直接跟在第i个区间的后面,最开始相当于跟在空区间的后面,后来就是a[j+1]跟在a[j]的后面组成区间
2.找到j之前选择i-1个区间的最优值+新开一个区间[j,j].

假如现在是第i轮区间选择:

dp[j]: 当前轮第j个位置的两种选择情况的最大值
mx:实时保存本轮在第j个位置选择后的最优值,当前轮的最优值
best[j-1]:上一轮在区间[1,j-1]选取i-1个区间的最优值,best[]是一个滚动数组,保存当前轮的最优值在下一轮使用

遇到的问题

找到j之前选择i-1个区间的最优值应该怎么处理呢?
当我们进行一轮新区间的时候,我们要使用到上一轮的j之前的最优值,同时又要保存j之前选取新区间之后的最优值
第一轮区间选择,其j之前的最优值都是0,因为只选取了0个区间
当我们用了上一轮的best[j-1],紧接着就要更新下一轮的best[j-1],此处具体看代码

AC代码

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1e6+100;
typedef long long ll;
int M,N;
int arr[maxn];//原数组
ll best[maxn],dp[maxn];//best上一轮的最优值,本轮dp[j]:本轮选择了j位置的最优值
int main(){
    while(~scanf("%d %d",&M,&N)){
        memset(best,0,sizeof(ll)*N+10);
        memset(dp,0,sizeof(ll)*N+10);
        ll mx;
        for(int i = 1;i<=N;i++) scanf("%d",&arr[i]);
        for(int i = 1;i<=M;i++){//轮次
            mx = -1e18;
            for(int j = i;j<=N;j++){
                dp[j] = max(dp[j-1],best[j-1])+arr[j];//选择j位置后的最优值,使用掉上一轮best[j-1]
                best[j-1] = mx;//保存本轮的j-1的最优值,放在下一轮用
                mx = max(mx,dp[j]);//更新本轮j位置的最优值
            }
        }
        printf("%lld\n",mx);
    }

    return 0;
}
全部评论

相关推荐

HR_丸山彩同学:你的项目描述里,系统设计讲了很多:MemCube是什么、三级存储架构怎么设计、四种遗忘策略分别是什么。这些面试的时候讲没问题,但简历上不需要这么细。 简历要突出的是影响力,不是实现细节。面试官看简历的时候想知道的是「这个项目有多大价值」,不是「这个项目具体怎么实现的」。实现细节是面试时候聊的 怎么改:技术细节可以精简为一句「采用三级存储架构+四种遗忘策略」,把省出来的篇幅用来写影响力。比如:项目有没有开源?有没有写成技术博客?有没有被别人使用过? 校园经历没有任何信息量,任何人都可以写这句话,写了等于没写。更关键的是,你投的是技术岗,校园活动经历本来就不是加分项。如果非要写,必须写出具体的数字和成果。如果你没有这些数字,那就老老实实删掉 「端到端耗时缩减30-40%」要给出确切数字和绝对值。从1000ms降到600ms是降了40%,从100ms降到60ms也是降了40%,但这两个含义完全不一样。其他也是,涉及到数据,准备好证据,口径统一,面试会问 「熟练」「熟悉」「了解」混在一起用,读起来很乱。而且「了解前端需求」最好改成「具备前后端协作经验」
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务