此题是一个最大的子段和的问题。

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

                     t1     t2 
d(A) = max{ ∑ai + ∑aj | 1 <= s1 <= t1 < s2 <= t2 <= n }
i=s1 j=s2


Your task is to calculate d(A).

这道题用最原始的方法就是硬搜,当然我们也必然知道硬搜的方法必然是要悲剧的。因为这样要产生非常多的时间复杂度。比如枚举中间的元素,然后分别搜索出以这个元素向左以及向右的分问题的字段和,找出这些中间元素中的最大值即可。但是以中间元素为n/2为例,搜左面与搜右面差不多的话,就是n²的量级了,然而这道题能给到5万,然后就悲剧了……

这道题目交单的方法就是动态规划,可以减到o(n).具体方法如下:

首先记录从左边开始的每一个元素为中点的最长上升序列的值,注意这要计算两次。首先把小于0的点断开,然后第二次计算时,就可以计算出以一个点为右上界的最长子段的长度。右边类似。最后计算怎样加能到最长即可。这样是0(cn)。

#include<iostream>
#include<stdlib.h>
using namespace std;
int compare(const void *x,const void *y)
{
    return *(int *)x-*(int *)y;//从小到大排序
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
    //cin.get();
int n;
scanf("%d",&n);
int a[50002]={};
int left[50002]={};
int right[50002]={};
int i;
int num=0;
for(i=1;i<=n;i++)
{
    scanf("%d",&a[i]);
    if(a[i]>=0)num++;
}
bool ind=false;
if(num<2)
{
    /*qsort(a+1,50001,sizeof(a[0]),compare);
    for(i=1;i<=n;i++)
        if(a[i]>=0)
            {
            int res=a[i]+a[i+1];
            printf("%d\n",res);
            ind=true;
            break;
            */
    ind = true;
    int temp=0;
    for(i=1;i<=n;i++)
        for(int j=1;j<n-i;j++)
        if(a[j]<a[j+1])
        {temp=a[j];
        a[j]=a[j+1];
        a[j+1]=temp;
        }
    cout<<a[1]+a[2]<<endl;
}
if(!ind)
{
    int suml=0;
    for(i=1;i<=n;i++)
    {
        if(left[i-1]>0)
                left[i]=left[i-1]+a[i];
            else left[i]=a[i];

    }
    for(i=1;i<=n;i++)
    {
        if(left[i]>suml)
                suml=left[i];
            else left[i]=suml;

    }
    right[n+1]=0;
    int sumr=0;
    for(i=n;i>=1;i--)
    {
        if(right[i+1]>0)
            right[i]=right[i+1]+a[i];
        else right[i]=a[i];
    }
    for(i=n;i>=1;i--)
    {
        if(right[i]>sumr)
                    sumr=right[i];
                else right[i]=sumr;
    }
    int max=-1000000;
    for(i=1;i<n;i++)
    {
        if(left[i]+right[i+1]>max)
            max=left[i-1]+right[i];
    }
    cout<<max<<endl;
}
}
return 0;
}

posted on 2010-05-21 20:36  梦涵  阅读(380)  评论(0编辑  收藏  举报