【题解】最大 M 子段和 Max Sum Plus Plus [Hdu1024] [51nod1052]

传送门:最大 \(M\) 子段和 \(Max\) \(Sum\) \(Plus\) \(Plus\) \([Hdu1024]\) \([51nod1052]\)

【题目描述】

给出一个长度为 \(N\) 的序列 ,将这 \(N\) 个数划分为互不相交的 \(M\) 个子段,并使得 \(M\) 个子段的和最大。

【样例】

样例输入:
7 2
-2
11
-4
13
-5
6
-2 样例输出:
26

【数据范围】

\(100\%\) \(1 \leqslant N \leqslant 10^6\)


【分析】

在 \(51nod\) 里面这道题的数据水出了一种极其诡异的境界,首先是它题目里瞎扯的一个特判没毛用,其次,我尝试了不下 \(10\) 种错误写法(包括不同题意所造成的不同写法),居然全对 \(...\)

设 \(dp[i][j]\) 表示使用前 \(j\) 个数划分了 \(i\) 段的最大和。

由于所选段不一定要连续,所以 \(dp[i][j]=dp[i][j-1]\),即第 \(i\) 段不选 \(a[j]\) 的情况。

如果要选 \(a[j]\) ,那么应该是从 \(a[j]\) 往前选出连续的一段 \([k+1,j]\) 作为第 \(i\) 段,即 \(dp[i][j]=max\{dp[i-1][k]+S[j]-S[k]]\}\),其中 \(k \in[i-1,j-1],\) 为了保证这之后剩下的数可以足够选完 \(m\) 段,需要满足 \(i-j \geqslant m-n\) 即 \(j \in [i,n-m+i]\),\(S[i]\)为 \(a[i]\) 的前缀和 。

开一个滚动数组 \(f\) 优化掉第一维,就成了酱紫: \(dp[j]=\begin{cases} max_{k=i-1}^{j-1}\{f[k]-S[k]]\}+S[j] & j=i\\max\{dp[j-1],{max_{k=i-1}^{j-1}\{f[k]-S[k]]\}+S[j]}\} & j>i \end{cases}\)

对于上面 \(j=i\) 的情况,实际操作时,可以特判,也可以直接 \(dp[i-1]=-inf\) 。

后面那一大堆求最大值的表达式可以直接用一个变量 \(maxs\) 来保存,初始值为 \(f[i-1]-S[i-1]\),每求完一个 \(dp[j]\),就让其与 \(f[j]-S[j]\) 取个最大值,下一次 \(dp[j+1]\) 要使用 \(maxs\) 时,其维护的区间信息恰好为 \([i-1,(j+1)-1]\) 。


【Code】

#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register LL
using namespace std;
const int N=1e6+3;
LL n,m,tmp,ans,maxs,S[N],f[N],dp[N];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
int main(){
while(scanf("%lld%lld",&m,&n)!=EOF){
for(Re i=1;i<=n;++i)in(S[i]),tmp+=(S[i]>0),S[i]+=S[i-1];
memset(dp,0,sizeof(dp));
memset(f,0,sizeof(f));
for(Re i=1;i<=m;++i){
for(Re j=1;j<=n;++j)f[j]=dp[j];
maxs=f[i-1]-S[i-1];
dp[i-1]=-1e18;
for(Re j=i;j<=n-m+i;++j){
dp[j]=max(dp[j-1],maxs+S[j]);
maxs=max(maxs,f[j]-S[j]);
}
}
printf("%lld\n",dp[n]);
}
}

【题解】最大 M 子段和 Max Sum Plus Plus [Hdu1024] [51nod1052]的更多相关文章

  1. 最大子段和(Max Sum)

    Max Sum. The following is an instance. a)    (-2,11,-4,13,-5,-2) 思路: 最大子段和:给定一个序列(元素可正可负),找出其子序列中元素和 ...

  2. HDU 1024 Max Sum Plus Plus【动态规划求最大M子段和详解 】

    Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  3. HDOJ-1003 Max Sum(最大连续子段 动态规划)

    http://acm.hdu.edu.cn/showproblem.php?pid=1003 给出一个包含n个数字的序列{a1,a2,..,ai,..,an},-1000<=ai<=100 ...

  4. [ACM] hdu 1003 Max Sum(最大子段和模型)

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su ...

  5. (最大m子段和) Max Sum Plus Plus (Hdu 1024)

    http://acm.hdu.edu.cn/showproblem.php?pid=1024     Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/ ...

  6. HDU 1003:Max Sum(DP,连续子段和)

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su ...

  7. HDU 1024:Max Sum Plus Plus(DP,最大m子段和)

    Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  8. HDU 1024 Max Sum Plus Plus(m个子段的最大子段和)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1024 Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/ ...

  9. hdu 1024 Max Sum Plus Plus (子段和最大问题)

    Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

随机推荐

  1. find、locate、whereis、which和type

    1. find $ find . -name '*' 2. locate 很快速的搜寻档案系统内是否有指定的档案,比find要快很多 其方法是先建立一个包括系统内所有档案名称及路径的资料库,之后当寻找 ...

  2. bat 获取管理员权限,判断系统位数,获取当前文件所在目录,regsvr32注册DLL、OCX

    1.获取管理员权限 @echo off if exist "%SystemRoot%\SysWOW64" path %path%;%windir%\SysNative;%Syste ...

  3. linux的性能调优

    单机调优: 分析性能瓶颈的原因,解决它.   cpu子系统 内存子系统 IO子系统 网络系统       @cpu子系统调优 cpu技术指标 xeon E5520 2.27GHz 8192kb # c ...

  4. Two-Stream Adaptive Graph Convolutional Network for Skeleton-Based Action Recognition

    Two-Stream Adaptive Graph Convolutional Network for Skeleton-Based Action Recognition 摘要 基于骨架的动作识别因为 ...

  5. css ie bug 双边距

  6. JDOJ 2982: 最大连续子段和问题

    洛谷 P1115 最大子段和 洛谷传送门 JDOJ 2982: 最大连续子段和问题 JDOJ传送门 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大. 输入格式 第一行是一个正整数NN, ...

  7. 每天一道Rust-LeetCode(2019-06-02)

    每天一道Rust-LeetCode(2019-06-02) Z 字形变换 坚持每天一道题,刷题学习Rust. LeetCode原题 Z 字形变换 题目描述 将一个给定字符串根据给定的行数,以从上往下. ...

  8. OpenCV 学习笔记(15)openc解帧视频

    1 修改读取视频的地址 2 修改保存图片序列的路径 String videopath = "F:/dongdong/0tool/3D/2模型/相机阵列/1_12cam亿级相机/数据/giga ...

  9. [RN] React Native 使用 teaset(Drawer)实现侧边菜单

    https://www.cnblogs.com/crazycode2/p/9537518.html

  10. python paramiko与linux的连接

    两种使用paramiko连接到linux服务器的代码 方式一: 1 ssh = paramiko.SSHClient() 2 ssh.set_missing_host_key_policy(param ...