1050 循环数组最大子段和

个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列)。当所给的整数均为负数时和为0。

例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。

Input

第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N+1行:N个整数 (-10^9 <= S[i] <= 10^9)

Output

输出循环数组的最大子段和。

Input示例

6
-2
11
-4
13
-5
-2

Output示例

20

第一次以每个元素作为起点求所有可能,遍历一遍,复杂度n*n,超时。后来看了网上的解法,复杂度n。最大字段和循环序列有两种情况,一是中间某部分和最大,无跨越情况,如 -1 2 3 5 -2,最大和是10,另一种情况是由首位两段组成如 3 5 -100 -200 1,最大和为9。第一种情况易解,第二种情况只需求出中间部分的最小值,然后用数组所有元素和减去即可。正解:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
#define maxn 1000005
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define INF 1000000000
int a[maxn] ;
int n;
int main()
{
    while(scanf("%d" , &n) != EOF)
    {
        int flag = 0;
        LL sum = 0 , all = 0;
        for(int i = 0; i < n ; i ++)
        {
            scanf("%d" , &a[i]);
            all += a[i];
        }
        LL maxx = 0;
        for(int i = 0 ; i < n ; i ++)
        {
            sum += a[i];
            if(sum > maxx) maxx = sum;
            if(sum < 0) sum = 0;
        }
        for(int i = 0 ; i < n ; i ++) a[i] = -a[i];
        sum = 0 ;
        LL maxx2 = 0;
        for(int i = 0 ; i < n ; i ++)
        {
            sum += a[i];
            if(sum > maxx2) maxx2 = sum;
            if(sum < 0) sum = 0;
        }
        printf("%lld\n" ,max(maxx , maxx2 + all));
    }
    return 0;
}
错解:
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define LL long long
using namespace std;
/*
sum[j+1] = d[j+1] + sum[j]>0?sum[j]:0;
有一个n2复杂度的方法。__数组开太大了。。

*/
#define MAXN 50001
LL a[MAXN];
//LL dp[MAXN];dp[i] 从i开始的最大值
LL n,ans=-MAXN,temp,result;//temp记录sum[j],ans记录结果
int main()
{
    scanf("%lld",&n);
    for(LL i=0;i<n;i++)
    {
        scanf("%lld",&a[i]);
    }
    for(LL i=0;i<n;i++)
    {
        temp = a[i];
        for(LL j=i+1,cnt=1; cnt<n; cnt++,j=(j+1)%n)
        {
            temp = a[j] + (temp>0?temp:0);
            //cout<<a[j]<<endl;
            ans = max(ans,temp);
        }
        result = max(ans,result);
        ans = -MAXN;
        //cout<<endl<<endl<<dp[i]<<endl<<endl;
    }
    //<<endl;
    printf("%lld\n",result);
    return 0;
}

 
时间: 2024-07-31 14:21:45

1050 循环数组最大子段和的相关文章

51nod 1050 循环数组最大子段和【环形DP/最大子段和/正难则反】

1050 循环数组最大子段和 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题  收藏  关注 N个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列).当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13.和为20. Input 第1

51Nod 1050 循环数组最大子段和 | DP

Input示例 6 -2 11 -4 13 -5 -2 Output示例 20 分析: 有两种可能,第一种为正常从[1 - n]序列中的最大子字段和:第二种为数组的total_sum - ([1-n]序列中的最短序列和) 最后结果为 max { 第一种, 第二种}. 对于第二种: 循环数组求最大子段和,可能出现中间的一部分不要,要两边的数.比如:-1 4 -1 -5 5 -2 1 -1 3,他的最大子段和就为 左边的-1 4加上右边的5 -2 1 -1 3,也就是,去掉1 -5这一段后的结果.而

51nod 1050 循环数组最大子段和

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1050 题意: 思路: 情况无非分为两种: ①正常的最大子段和. ②首尾相连的最大子段和,此时中间的那段肯定是最小子段和,用总的sum-最小子段和即可. 最后比较两者大小. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio>

51nod 1050 循环数组最大子段和 (dp)

http://www.51nod.com/onlineJudge/questionCode.html#problemId=1050&noticeId=13385 参考:http://blog.csdn.net/acdreamers/article/details/38760805 #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; int n; ll a[100001

循环数组最大子段和(动态规划思想的巧妙转换)

个人心得:这是一道好题,线性的最大字段和在动态规划中是司空见惯的.所以对于这种动态规划的思想的巧妙转变也是需要 锻炼的,就像在暑假集训里面碰到的从1到k是递增,k到n是递减的k使得此时的和最大,当时也是毫无办法,虽然后面 想到了分别将首尾展开然后分别求递增的最大和,题目就迎刃而解了.其实这一题题目的分解还是很明白的, 最大值无非就是线性动态规划和横跨俩端的子段,横跨俩端的子段最简单就是俩层循环很明显超时了,后面想着从左边找到最大 的并标志,但是很明显俩段最大值不一定是在一段最大值的前提下,所以后

[51NOD1959]循环数组最大子段和(dp,思路)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1050 这道题的最大子段和有两种可能,一种是常规的子段和,另一种是从结尾到开头的一个子段.常规做是一种可能,另一种带循环的则可以认为是序列中间有一段最小子段和,把这段最小子段和去掉,剩下的可能就是最大子段和了. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL;

51Nod1050 循环数组最大子段和

Problem N个整数组成的循环序列a[1],a[2],a[3],-,a[n],求该序列如a[i]+a[i+1]+-+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列).当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13.和为20. Solution 最大字段和最大,或者去掉中间某个最小字段和剩下的最大. Code #include<stdio.h> #inc

循环数组最大子段和

记得以前好像做过,应该是学长给了个思路才想出来的,明明是一道水题,写了半天全是错的,给自己留个纪念吧,思路很简单:把数组复制一遍接到数组后面,先求最大值 ,要是直接求的话肯定错,个数要限制一下,给个例子:4 5 6 7 ,复制之后是 4 5 6 7 4 5  6 7 要是没有个数限制的话就全加上了,之后这个先来一个候选值,因为不一定对 例子是: 1 2 3  -5 3  2 1,自己跑一遍的话可以知道是3 + 2 + 1 + 1 + 2 + 3之前写的会全加上,这个就要另一个思路了,就是反其道而

51NOD1050 循环数组最大字段和

N个整数组成的循环序列a11,a22,a33,…,ann,求该序列如aii+ai+1i+1+…+ajj的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑an−1n−1,ann,a11,a22这样的序列).当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13.和为20. Input第1行:整数序列的长度N(2 <= N <= 50000) 第2 - N+1行:N个整数 (-10^9 <= Sii <= 10^9)O