hdu 1024 max sum plus plus

刚写这题时知道是dp但动态转移方程推不出来,后来上网上搜了题解。

先把问题简化,假如就选一段,这就是个经典的max sum dp。

状态转移方程为dp[i]=dp[i-1]+a[i]>a[i]?:dp[i-1]+a[i]:a[i];

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1003

再说这道题http://acm.hdu.edu.cn/showproblem.php?pid=1024;

题意是求不相交且连续的多个子列和的最大值。由一段找最大然后可以想到开一个二维数组dp[i][j];每个状态可理解为分为i段时第j个元素选入时的最大值,所以要么选第j个数时在上一层的基础上从新将第j个数开为一段,要么在本层的基础上加上第j个数,又应为是要最优,自然就要最大,所以得状态转移方程dp[i][j]=max(dp[i][j-1]+a[j],max(dp[i-1][k])+a[j](i-1<=k<j));

由于给的范围很大<=1000000;开2维的数组爆内存,所以是否一维的可以,我一开始想时是开两个数组交替,反正只和本层和上层有关,但太麻烦,要交替赋值,时间耗费大。

没次的更新需要用到上一层的到i-1~j-1为止的最大值,所以可以开个数组记录;方程就变成dp[j]=max(dp[j-1]+a[j],pre[j]+a[j]);

最后找dp[n]~dp[p]的最大就行了,n为要分的段,p为元素总个数。

下面看两段代码:

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<string.h>
 5 #include<stdlib.h>
 6 #include<math.h>
 7 using namespace std;
 8 typedef long long ll;
 9 ll a[1000005];
10 ll aa[1000005];//dp数组
11 ll b[1000005];//记录i-1~j-1的最大值数组
12 //ll pp[1000005];
13 int main(void)
14 {
15     ll i,j,k,p,q,l,n,m;
16     while(scanf("%lld",&m)!=EOF)
17     {
18         scanf("%lld",&p);
19         if(m>p)//m不可能超过p
20         {
21             m=p;
22         }
23         for(i=1; i<=p; i++)
24         {
25             scanf("%lld",&a[i]);
26         }
27 
28         aa[0]=0;
29         memset(b,0,sizeof(b));//每一次b都要初始化
30         for(i=1; i<=m; i++)
31         {
32             for(j=i; j<=p; j++)
33             {
34                 aa[j]=aa[j-1]+a[j]>b[j]+a[j]?aa[j-1]+a[j]:b[j]+a[j];
35 
36             }
37             b[i]=aa[i];//本层循环完后更新b数组每次更新要从第i个数开始因为要分成i+1段就必须从能分成i段时加一个数,而分i段必须要i个数。
38             for(j=i+1; j<=p; j++)
39             {
40                 b[j]=aa[j-1]>b[j-1]?aa[j-1]:b[j-1];
41             }
42         }
43         ll maxx=aa[m];
44 
45         for(i=m; i<=p; i++)
46         {
47             if(maxx<aa[i])
48             {
49                 maxx=aa[i];
50             }
51         }
52 
53         printf("%lld
",maxx);
54 
55     }
56 
57     return 0;
58 
59 }
 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<string.h>
 5 #include<stdlib.h>
 6 #include<math.h>
 7 using namespace std;
 8 typedef long long ll;
 9 ll a[1000005];
10 ll aa[1000005];
11 ll b[1000005];
12 //ll pp[1000005];
13 int main(void)
14 {
15     ll i,j,k,p,q,l,n,m;
16     while(scanf("%lld",&m)!=EOF)
17     {
18         scanf("%lld",&p);
19         if(m>p)
20         {
21             m=p;
22         }
23         for(i=1; i<=p; i++)
24         {
25             scanf("%lld",&a[i]);
26         }
27 
28         aa[0]=0;
29         memset(b,0,sizeof(b));
30         for(i=1; i<=m; i++)
31         {
32             for(j=i; j<=p; j++)
33             {
34                 aa[j]=aa[j-1]+a[j]>b[j]+a[j]?aa[j-1]+a[j]:b[j]+a[j];
35                 if(j==i)
36                 {
37                     b[j]=aa[i];
38                 }
39                 else
40                 {
41                     b[j]=aa[j-1]>b[j-1]?aa[j-1]:b[j-1];//此处优化了一下b的更新直接和aa的更新合并并不要在开一重,提高了代码的效率。
42                     //因为当前是更新aa[j]所以b[j]记录的是i-1到j-1的最大更新完aa后再更新b并不影响aa[j+1]的更新b[j+1]还是上一层的更新完才变本层的。
43                 }
44 
45             }
46 
47         }
48         ll maxx=aa[m];
49 
50         for(i=m; i<=p; i++)
51         {
52             if(maxx<aa[i])
53             {
54                 maxx=aa[i];
55             }
56         }
57 
58         printf("%lld
",maxx);
59 
60     }
61 
62     return 0;
63 
64 }
油!油!you@
原文地址:https://www.cnblogs.com/zzuli2sjy/p/4922647.html