zoukankan      html  css  js  c++  java
  • 环状最大两段子段和

    传送门

    题意:

    简单说
    就是给个序列
    求和最大的两段
    且序列头可接尾

    解法:

    若不考虑环
    则可对每一个位置
    分成其前一段和其后一段
    求其前一段与后一段的最大最段和相加
    找到最大的值

    在考虑环的情况
    可以把原问题转化为求中间最小的两段
    再用序列全部的和 减去 最小的两段
    为了偷懒
    直接将序列所有数取相反数
    然后按照第一种做法做

    当然序列中只有一个正数和无正数时这么做就错了
    因为求出来的值需要至少有一个序列为空
    此时我们就并不需要做考虑环的操作
    直接输出不考虑环的值就行

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<map>
    #define inf 2000000000
    #define min(x,y) ((x)<(y)?(x):(y))
    #define max(x,y) ((x)>(y)?(x):(y))
    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define dwn(i,a,b) for(int i=(a);i>=(b);--i)
    using namespace std;
    typedef long long ll;
    int n,ans1,ans2,sum=0,tot=0,a[200010],f[200010],g[200010];
    int solve()
    {
        int ans=-inf;
        rep(i,1,n) f[i]=max(f[i-1],0)+a[i];
        dwn(i,n,1) g[i]=max(g[i+1],0)+a[i];
        rep(i,2,n) f[i]=max(f[i-1],f[i]);
        dwn(i,n-1,1) g[i]=max(g[i+1],g[i]);
        rep(i,1,n-1) ans=max(ans,f[i]+g[i+1]);
        return ans;
    }
    int main()
    {
        scanf("%d",&n);
        rep(i,1,n)
        {
            scanf("%d",&a[i]);
            sum+=a[i],tot+=(a[i]>0);
        }
        ans1=solve();
        if(tot<=1)
        {
            printf("%d
    ",ans1);
            return 0;
        }
        rep(i,1,n) a[i]=-a[i];
        ans2=sum+solve();
        printf("%d
    ",max(ans1,ans2));
        return 0;
    }
    
    
  • 相关阅读:
    轮询算法
    随机算法
    加权随机算法
    平滑加权轮询算法
    预训练模型与Keras.applications.models权重资源地址
    多通道卷积操作解析
    Squeeze-and-Excitation Networks
    实验数据集概况
    Keras-图片预处理
    Keras常用层
  • 原文地址:https://www.cnblogs.com/MYsBlogs/p/11042512.html
Copyright © 2011-2022 走看看