循环数组最大子段和

  记得以前好像做过,应该是学长给了个思路才想出来的,明明是一道水题,写了半天全是错的,给自己留个纪念吧,思路很简单:把数组复制一遍接到数组后面,先求最大值

,要是直接求的话肯定错,个数要限制一下,给个例子: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之前写的会全加上,这个就要另一个思路了,就是反其道而行,找序列中连续最小的然后不要了,感觉很

神奇,这两个候选值选一个最大的就可以了。

代码:

  

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
int x[500000];
int main()
{
    int n;
    scanf("%d",&n);
    ll fuck=0;
    for(int i=0;i<n;i++){
        scanf("%d",&x[i]);
        x[n+i]=x[i];
        fuck+=x[i];
    }
    //for(int i=0;i<n*2;i++)  printf("%d\n",x[i]);
    ll maxx=0;
    ll sum=0;
    int ge=0;
    for(int i=0;i<n*2;i++){
        if(x[i]+sum>0){
            sum+=x[i];
            maxx=max(maxx,sum);
            ge++;
            if(ge==n){
                sum=0;
                ge=0;
            }
        }
        else{
            sum=0;
            ge=0;
        }
    }
    maxx=max(sum,maxx);
    ll haha=maxx;
    maxx=0;
    ge=0;
    sum=0;
    for(int i=n*2-1;i>=0;i--){
        if(x[i]+sum>0){
            sum+=x[i];
            maxx=max(maxx,sum);
            ge++;
            if(ge==n){
                sum=0;
                ge=0;
            }
        }
        else{
            sum=0;
            ge=0;
        }
    }
    maxx=max(maxx,sum);
    haha=max(maxx,haha);
    ll minn=10000000000;
    sum=0;
    for(int i=0;i<n*2;i++){
        if(x[i]+sum<0){
            sum+=x[i];
            minn=min(minn,sum);
            ge++;
            if(ge==n){
                sum=0;
                ge=0;
            }
        }
        else{
            sum=0;
            ge=0;
        }
    }
    ll lala=minn;
    minn=10000000000;
    sum=0;
    for(int i=n*2-1;i>=0;i--){
        if(x[i]+sum<0){
            sum+=x[i];
            minn=min(minn,sum);
            ge++;
            if(ge==n){
                sum=0;
                ge=0;
            }
        }
        else{
            sum=0;
            ge=0;
        }
    }
    lala=min(minn,lala);
    fuck-=lala;
    haha=max(haha,fuck);
    printf("%lld\n",haha);
    return 0;
}

原文地址:https://www.cnblogs.com/fzw1523/p/10659509.html

时间: 2024-10-09 11:24:19

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

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

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] <

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

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

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这一段后的结果.而

[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

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

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