51nod 1052 最大M子段和(动态规划)

分析:记dp[x][s][1]为从第x个数开始,剩余s段可以分,1表示x跟上一段连着,0表示不连着,递推式为dp[x][s][1]=max{dp[x+1][s][1]+a[x],dp[x+1][s][0]},dp[x][s][0]=max{dp[x+1][s-1][1]+a[x],dp[x+1][s][0]}.

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 const int maxn=5005;
 5 typedef long long ll;
 6 ll dp[2][maxn][2];
 7 int n,m,a[maxn];
 8 int main(){
 9     cin>>n>>m;
10     memset(dp,0,sizeof(dp));
11     for(int i=0;i<n;i++)
12         cin>>a[i];
13     for(int i=0;i<=m;i++){
14         dp[0][i][1]=max(0,a[n-1]);
15         if(i==0)continue;
16         dp[0][i][0]=max(0,a[n-1]);
17     }
18     for(int i=0;i<n-1;i++){
19         for(int j=0;j<=m;j++){
20             dp[(i+1)%2][j][1]=max(dp[i%2][j][1]+a[n-2-i],dp[i%2][j][0]);
21             if(j>0)dp[(i+1)%2][j][0]=max(dp[i%2][j-1][1]+a[n-2-i],dp[i%2][j][0]);
22             else dp[(i+1)%2][j][0]=dp[i%2][j][0];
23         }
24     }
25     if(n%2==0)cout<<max(dp[1][m-1][1],dp[1][m][0])<<endl;
26     else cout<<max(dp[0][m-1][1],dp[0][m][0])<<endl;
27     return 0;
28 }
时间: 2024-10-22 16:12:40

51nod 1052 最大M子段和(动态规划)的相关文章

51nod 1052最大M子段和 &amp; poj 2479最大两子段和

最大子段和经典问题的扩展. 题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1052 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. Input 第1行:2个数N和M,中间用空格分

51nod 1052 最大M子段和

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行:2个数N和M,中间用空格分隔.N为整数的个数,M为划分为多少段.(2 <= N , M <= 5000) 第2 - N+1行:N个整数 (-10^9 <= a[i] <= 10^

51nod1053&amp;&amp;1052 最大M子段和

题面 我们先将所有连续正段和连续负段合并,那么选取所有正段一定是最优的,但是选取的段数有可能超过$m$段,这时我们就需要合并. 1.选取不在两端的一个负段与它两边正段合并,块数减少$1$,子段和减少$|v[i]|$. 2.选取一个正段,将其删除,并与其左右负段合并,块数减少$1$,子段和减少$|v[i]|$. 所以我们将每段按照$|v[i]|$大小排序,每次贪心合并至段数小于等于$m$. 1 #include <iostream> 2 #include <stdio.h> 3 #i

51nod 1065 最小正子段和

题目链接:51nod 1065 最小正子段和 房教说用前缀和做,然后看了别人博客懂了后就感觉,这个真有意思... 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N = 50001; 6 const int inf = 0x3f3f3f3f; 7 pair<long long, int> sum[N]; 8 int

1052 最大M子段和

1052 最大M子段和 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. Input 第1行:2个数N和M,中间用空格分隔.N为整数的个数,M为划分为多少段.(2 <= N , M <= 5000) 第2 - N+1行:N个整数 (-10^9 <= a[

51nod 1052 (dp)

最大M子段和 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. Input 第1行:2个数N和M,中间用空格分隔.N为整数的个数,M为划分为多少段.(2 <= N , M <= 5000) 第2 - N+1行:N个整数 (-10^9 <= a[i] &l

51nod 1053 最大M子段和 V2

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行:2个数N和M,中间用空格分隔.N为整数的个数,M为划分为多少段.(2 <= N , M <= 50000) 第2 - N+1行:N个整数(-10^9 <= a[i] <= 10^

51Nod 1083 矩阵取数问题 | 动态规划

#include "bits/stdc++.h" using namespace std; #define LL long long #define INF 0x3f3f3f3f3f #define PI acos(-1) #define N 510 #define MOD 10 using namespace std; int arr[N+1][N+1],dp[N+1][N+1]; int main() { int n; while(~scanf("%d",&am

51nod 1065 最小正子段和 (贪心)

题目:传送门. 题意:中文题. 题解:求前缀和,并且标记每个数的下标,按照前缀和大小进行从小到大排序.随后进行遍历,如果满足下标data[i-1].id<data[i].id&&data[i-1].val<data[i].val:就更新最小值,因为是相近的,所以已经是最小值候选了,其余的绝对不可能了.那么为什么只考虑相邻的呢?因为如果A到B不能形成队列,A到C形成队列了,那么B到C一定是比A到C的数值更小,而且还一定能够形成队列(A与B不能形成队列,说明posA>posB