P1121 环状最大两段子段和

132 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

题目:给出一段长度为 n 的环状序列 a,即认为 a1 和 an 是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大。
思路: 两种情况
1.000----000---000
2.----0000---000---
0代表选了这个数,-代表没选;第二种情况可以由正着求一遍再反着求一遍最大子段和,然后枚举断点拼接;第一种可以换一个思路求出最小的两段然后用总和减去就可以了,为了方便可以直接让a[i]取负再跑一遍就行
这是子段和的方法

#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define CHECK(x,y) (x>0&&x<=n&&y>0&&y<=m)
//#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int n,sum=0,a[200005],tot=0,f[200005],g[200005];
 
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    memset(f,-64,sizeof(f));
    for(int i=1;i<=n;i++)f[i]=max(f[i-1],0)+a[i];
    for(int i=1;i<=n;i++)f[i]=max(f[i],f[i-1]);
    int maxx=-inf;
    for(int i=1;i<=n;i++)
        maxx=max(maxx,f[i]);
    cout<<maxx<<endl;
    return 0;
}

这是题解代码

#include<bits/stdc++.h>
//#pragma-GCC-optimize("-Ofast");
#define ll long long
#define int long long
#define lowbit(x) ((x)&(-x))
#define endl '\n'
using namespace std;
const ll mod=998244353;
const ll inf=1e9;
const double pi=acos(-1);
const int N=1e6+100;
ll qpow(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a){return qpow(a,mod-2);}
int n,a[200005],f[200005],g[200005];
int ask(){
    for(int i=1;i<=n;i++) f[i]=max(f[i-1],0LL)+a[i];
    for(int i=1;i<=n;i++) f[i]=max(f[i-1],f[i]);
    for(int i=n;i>=1;i--) g[i]=max(g[i+1],0LL)+a[i];
    for(int i=n;i>=1;i--) g[i]=max(g[i+1],g[i]);
    int res=-inf;
    for(int i=1;i<=n;i++) res=max(res,f[i]+g[i+1]);
    return res;
}
signed main()
{
    //ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    int zn=0,sum=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        sum+=a[i];
        if(a[i]>0) zn++;
    }
    memset(f, ~0x7f, sizeof(f));
    memset(g, ~0x7f, sizeof(g));
    int ans=ask();
    if(zn==1){cout<<ans<<endl;return 0;}
    for(int i=1;i<=n;i++) a[i]*=-1;
    ans=max(ans,(sum+ask())?(sum+ask()):-inf);
    cout<<ans<<endl;
    return 0;
}