百练2479:Maximum sum

Maximum sum
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 41559 Accepted: 12981

Description

Given a set of n integers: A={a1, a2,..., an}, we define a function d(A) as below:
Your task is to calculate d(A).

Input

The input consists of T(<=30) test cases. The number of test cases (T) is given in the first line of the input. 
Each test case contains two lines. The first line is an integer n(2<=n<=50000). The second line contains n integers: a1, a2, ..., an. (|ai| <= 10000).There is an empty line after each case.

Output

Print exactly one line for each test case. The line should contain the integer d(A).

Sample Input

1

10
1 -1 2 2 3 -3 4 -4 5 -5

Sample Output

13

Hint

In the sample, we choose {2,2,3,-3,4} and {5}, then we can get the answer. 

Huge input,scanf is recommended.

Source

POJ Contest,Author:Mathematica@ZSU
***********************************************
好吧,我得承认,这道题的算法我并没有看懂。。连续最大子段和问题是基本算法,找了网上的算法:
int MaxSub (int a[])  
{    
    int dp[N], max, i;    
    max = dp[0] = a[0];    
    for (i=1; i<N; i++)    
    {    
        if (dp[i-1] > 0)    
            dp[i] = dp[i-1] + a[i];    
        else    
            dp[i] = a[i];    
        if (dp[i] > max)    
            max = dp[i];    
    }    
    return max;    
}  
dp[i]表示有a[i]参与的情况下某段序列的和。若前面的序列和dp[i-1]大于0,则把当前a[i]加到前面序列和dp[i-1]上,反之,则从a[i]处另起一段,赋给dp[i]。我就是这里不理解。为什么要根据dp[i-1]判断而不是a[i]呢?记下来吧,万一考呢。下面是这道题的算法:
//poj 2479 Maximum sum  
//2013-05-01-17.26  
#include <stdio.h>  
#include <string.h>  
#include <algorithm>  
using namespace std;  
const int maxn = 50005;  
int dplift[maxn];  
int dpright[maxn];  
int a[maxn];  
  
int main()  
{  
    int t, n;  
    scanf("%d", &t);  
    while (t--)  
    {  
        scanf("%d", &n);  
        for (int i = 1; i <= n; i++)  
        {  
            scanf("%d", &a[i]);  
        }  
  
        dplift[1] = a[1];  
        for (int i = 2; i <= n; i++)  
        {  
            if (dplift[i-1] > 0)  
                dplift[i] = dplift[i-1] + a[i];  
            else  
                dplift[i] = a[i];  
        }  
        for (int i = 2; i <= n; i++)  
            dplift[i] = max(dplift[i], dplift[i-1]);  
  
        dpright[n] = a[n];  
        for (int i = n-1; i >= 1; i--)  
        {  
            if (dpright[i+1] > 0)  
                dpright[i] = dpright[i+1] + a[i];  
            else  
                dpright[i] = a[i];  
        }  
        for (int i = n-1; i >= 1; i--)  
            dpright[i] = max(dpright[i+1], dpright[i]);  
  
        int ans = dplift[1] + dpright[2];  
        for (int i = 2; i < n; i++)  
        {  
            ans = max(dplift[i]+dpright[i+1], ans);  
        }  
        printf("%d\n", ans);  
    }  
    return 0;  
}  
用dplift[i]保存第1到第i个之间的最大子段和,dpright[i]保存第i到第n个之间的最大子段和,最终结果就是dplift[i]+dpright[i+1]中最大的一个。注意后一段要倒着求。

这是另一版代码;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>

const int MAXN = 50010;
int an[MAXN];
int d1[MAXN], d2[MAXN];

int main()
{
    int cases;
    scanf("%d", &cases);
    while (cases--)
    {
        int n;
        scanf("%d", &n);

        for (int i = 1; i <= n; ++i)
            scanf("%d", &an[i]);

        int tmax = INT_MIN, temp = 0;
        for (int i = 1; i <= n; ++i)
        {
            temp += an[i];
            if (tmax < temp)
                tmax = temp;
            if (temp < 0)
                temp = 0;
            d1[i] = tmax;
        }
        tmax = INT_MIN, temp = 0;
        for (int i = n; i >= 1; --i)
        {
            temp += an[i];
            if (tmax < temp)
                tmax = temp;
            if (temp < 0)
                temp = 0;
            d2[i] = tmax;
        }

        int ans = INT_MIN;
        for (int i = 1; i < n; ++i)
            if (ans < d1[i] + d2[i+1])
                ans = d1[i] + d2[i+1];

        printf("%d\n", ans);
    }
    return 0;
}

侵删。。。。
***************************
坚持,胜利就在眼前~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值