【u124】环状最大两段子段和

Time Limit: 1 second
Memory Limit: 128 MB
【问题描述】

给出一段环状序列,即认为A[1]和A[N]是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大。

【输入格式】

输入文件maxsum2.in的第一行是一个正整数N,表示了序列的长度。 第2行包含N个绝对值不大于10000的整数A[i],描述了这段序列,第一个数和第N个数是相邻的。
【输出格式】

输入文件maxsum2.out仅包括1个整数,为最大的两段子段和是多少。
【数据规模】

对于40%的数据,有2 ≤ N ≤ 2000。 对于100%的数据,有N ≤ 200000。
Sample Input1

7

2 -4 3 -1 2 -4 3

Sample Output1

9

【样例解释】

一段为3 –1 2,一段为3 2

*2 -4 *3 *-1 *2 -4 *3

【题目链接】:http://noi.qz5z.com/viewtask.asp?id=u124

【题解】

假设最后的答案区间被涂上红色;则最后答案一定是以下两种形式;(把环看成是直线);
这里写图片描述
这里写图片描述
对于第一种情况,只要枚举两个区间的断点就可以了;
枚举前要用最大子段和问题的普通形式的数组弄个前缀和和后缀和;
枚举的时候左边和右边直接加起来就是两个红色部分的了;
而对于第二种情况
我们可以转换成求中间两段黑色的部分;让它的和最小;即求两段子段和最小;然后用总数减去它就是最大的了;
两种情况取最大值就好;
用第二种方法求解是有条件的;
即数组中的正数的个数要大于1个;
比如
没有正数
5
-1 -1 -1 -1 -1
如果用了第二种答案为0(程序认为黑色部分两段和的最小值为-5而总和为-5…);正确答案是-2,第一种才能求出来;
只有一个正数也不行
5
-1 -1 -1 -1 5
第二种答案为5(两个最小部分和为-4,总和为1);但是如果答案为5的话就没有选出两段出来,因此正确答案为第一种求出来的4才对;

【完整代码】

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <set>
#include <map>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <string>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second

typedef pair<int,int> pii;
typedef pair<LL,LL> pll;

void rel(LL &r)
{
    r = 0;
    char t = getchar();
    while (!isdigit(t) && t!='-') t = getchar();
    LL sign = 1;
    if (t == '-')sign = -1;
    while (!isdigit(t)) t = getchar();
    while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
    r = r*sign;
}

void rei(int &r)
{
    r = 0;
    char t = getchar();
    while (!isdigit(t)&&t!='-') t = getchar();
    int sign = 1;
    if (t == '-')sign = -1;
    while (!isdigit(t)) t = getchar();
    while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
    r = r*sign;
}

const int MAXN = 2e5+100;
const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
const double pi = acos(-1.0);

int n;
int pltor[MAXN],ltor[MAXN],prtol[MAXN],rtol[MAXN],a[MAXN];
int pltor1[MAXN],ltor1[MAXN],prtol1[MAXN],rtol1[MAXN];

int main()
{
    //freopen("D:\rush.txt","r",stdin);
    int total=0,cnt=0;
    rei(n);
    rep1(i,1,n)
    {
        rei(a[i]);
        if (a[i]>0)
            cnt++;
        total+=a[i];
    }
    pltor[0]=-21e8;
    pltor1[0]=21e8;
    rep1(i,1,n)
    {
        ltor[i] = max(a[i],ltor[i-1]+a[i]);
        pltor[i] = max(pltor[i-1],ltor[i]);
        ltor1[i] = min(a[i],ltor1[i-1]+a[i]);
        pltor1[i] = min(pltor1[i-1],ltor1[i]);
    }
    prtol[n+1]=-21e8;
    prtol1[n+1]=21e8;
    rep2(i,n,1)
    {
        rtol[i] = max(a[i],rtol[i+1]+a[i]);
        prtol[i] = max(prtol[i+1],rtol[i]);
        rtol1[i] = min(a[i],rtol1[i+1]+a[i]);
        prtol1[i] = min(prtol1[i+1],rtol1[i]);
    }
    int ans1 = -21e8,ans2=21e8;
    rep1(i,1,n-1)
    {
        int temp = pltor[i]+prtol[i+1];
        ans1 = max(ans1,temp);
        temp = pltor1[i]+prtol1[i+1];
        ans2 = min(ans2,temp);
    }
    if (cnt>1 && total-ans2>ans1)
        ans1 = total-ans2;
    printf("%d
",ans1);
    return 0;
}
原文地址:https://www.cnblogs.com/AWCXV/p/7626907.html