杭电1024Max Sum Plus Plus

 地址:http://acm.hdu.edu.cn/showproblem.php?pid=1024

题目:

Problem Description
Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem.

Given a consecutive number sequence S 1, S 2, S 3, S 4 ... S x, ... S n (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ S x ≤ 32767). We define a function sum(i, j) = S i + ... + S j (1 ≤ i ≤ j ≤ n).

Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i 1, j 1) + sum(i 2, j 2) + sum(i 3, j 3) + ... + sum(i m, j m) maximal (i x ≤ i y ≤ j x or i x ≤ j y ≤ j x is not allowed).

But I`m lazy, I don't want to write a special-judge module, so you don't have to output m pairs of i and j, just output the maximal summation of sum(i x, j x)(1 ≤ x ≤ m) instead. ^_^
 

 

Input
Each test case will begin with two integers m and n, followed by n integers S 1, S 2, S 3 ... S n.
Process to the end of file.
 

 

Output
Output the maximal summation described above in one line.
 

 

Sample Input
1 3 1 2 3 2 6 -1 4 -2 3 -2 3
 

 

Sample Output
6 8
Hint
Huge input, scanf and dynamic programming is recommended.
 
 
一开始,题目都没看懂,(os:题目讲的什么鬼,英语差就是心酸= =)
后来看懂了题目意思后也没做出来,没想到那种dp方法,好心累,估计是dp题做得少的原因吧。。
之后看了看了几个人的博客,才会的,原地址 http://blog.csdn.net/lishuhuakai/article/details/8067474
还有一个的忘了。。。
先讲下题目意思吧:先讲下连续最大子段和,就是给你n个数,a[1]....1[n],求a[i]+.a[i+1]...+a[j]的最大值。
    此时状态转移方程:dp[i]=a[i]+(dp[i-1]>0?dp[i-1]:0)(dp【i】代表选了a【i】时的最大子段和)
       呃,不知道怎么表达了,上图吧:
    
dp[i]\a[i]2-13-89
12    
2 1   
3  4  
4   -4 
5    9
    对于连续最大和,只需要扫描一遍数组就好了
    1024题呢,就是把n个数分成x(x∈[m,n])段后,求这其中m个的子段和(不相交)的最大值;  
    由连续最大子段和的解法可以推广到求m个最大字段和,
             dp[i][j] = max(dp[i][j-1],max(dp[i-1][k]))+a[j];(i-1<=k<=j-1)
    其中dp【i】【j】时,前j个元素中取i个子段的最大和(一定取了a【j】)
    所以由dp[i][j-1]到dp[i][j] 时,有两种取法:
    1:a[j]和前一个以a[j-1]的子段合并
    2:独立成一个子段;
      以题目的第二组数据为例:
    
dp i\j)-14-23-23
1-142536
2\32758
3\\16510
4\\\449
5\\\\27
    
 
 
 
 
maxtemp\\\\\\
1-14455\
2\3377\
3\\166\
4\\\49\
5\\\\2\
 \\\ \\
 
 
 
 
 
   
没写的代表不用算。。。
    这样dp方程就有了,不过因为题目所给的数据较大,1 ≤ n ≤ 1,000,000,
    空间复杂度:m*n,很容易就超了
    时间复杂度:n^3,也是会超的
    所以继续优化,容易看出,每次使用dp方程时,其实只涉及到两个数组dp[i][k]和dp[i-1][k],所以可以化简为两个数组dp1[i],dp2[i]储存。
    这样空间复杂度就降低到m了
    然而时间复杂度没变,继续优化,我们可以用另一个数组maxtemp[i]来储存max(dp[i-1][k])(i-1<=k<=j-1),
    所以dp方程变为:
        dp[i][j] = max(dp[i][j-1],maxtemp[i-1])+a[j];
    这样时间复杂度就变成n^2了,可以接受了。
    其实,空间还可以优化,用一个dp数组就可以了,因为dp[i]从左向右递推时,只和dp[i-1],maxtemp[i-1]有关,
    所以可以删去dp2[i].
    上代码:
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cmath>
 5 #include <cstring>
 6 #include <queue>
 7 #include <stack>
 8 #include <map>
 9 #include <vector>
10 
11 #define N 1000010
12 #define PI acos((double)-1)
13 #define E exp(double(1))
14 using namespace std;
15 int dp1[N];
16 int maxtemp[N];
17 int a[N];
18 
19 int main(void)
20 {
21     int n, m, max1;
22     while (scanf("%d%d", &m, &n) == 2)
23     {
24         for (int i = 1; i <= n; i++)
25             scanf("%d", &a[i]);
26         dp1[1] = maxtemp[1] = max1 = a[1];
27         for (int i = 2; i <= n; i++)
28         {
29             if (max1 >= 0)
30             {
31                 dp1[i] =  a[i] + max1;
32                 max1 += a[i];
33             }
34             else
35             {
36                 dp1[i] = a[i];
37                 max1 = a[i];
38             }
39         }
40         for (int i = 2; i <= m; i++)
41         {
42             maxtemp[i-1] = dp1[i-1];
43             for (int j = i ; j < n; j++)
44             {
45                 if (maxtemp[j - 1]<dp1[j])
46                 {
47                     maxtemp[j] = dp1[j];
48                 }
49                 else
50                     maxtemp[j] = maxtemp[j - 1];
51             }
52             for (int j = i; j <= n; j++)
53             {
54                 if (i == j)
55                     dp1[j] = maxtemp[j - 1] + a[j];
56                 else
57                     dp1[j] = max(dp1[j - 1], maxtemp[j - 1]) + a[j];
58             }
59         }
60         max1 = dp1[m];
61         for (int i = m; i <= n; i++)
62             if (max1<dp1[i])
63                 max1 = dp1[i];
64         cout << max1 << endl;
65 
66     }
67     return 0;
68 }
View Code

 

转载于:https://www.cnblogs.com/weeping/p/5361145.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值