数学考试(牛客每日一题)变形一

题意
给一个长度为n的区间,找两个不相交的区间,区间的长度不确定。
思路
这个题和数学考试那一题唯一不同的是区间的长度不确定了。
在数学考试那个题中,我们是记录了一个maxn[i]
来表示i~n中的区间为k的最大值,现在区间不确定了。
maxn[i]=max(maxn[i+1],sum[j]-sum[i-1]) j>i.
原来j-i的区间是固定的,现在j不确定,但是我们如果想让sum[j]-sum[i-1]的值最大,我们肯定要尽量要让sum[j]最大,所以我们可以在维护一个maxsum[i]表示i~n 中的前缀和数组的最大值,
这样我们的maxn[i]就是维护的i~n中的区间和的最大值了。
但是左边那个区间1~i中因为区间不确定,所以我们还是需要两层循环来解决,但是其实并不需要,根据上面求右区间最大值的方法,我们也可以求出左区间最大值,所以最后的时间复杂度是o(n)的。

#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll a[N]; //原数组
ll sum[N]; //前缀和数组
ll maxnr[N]; // maxnr[i] 表示 i~n中的区间最大值。
ll maxsum[N]; // maxsum[i] 表示i~n中的前缀和最大值。
ll maxnl[N]; // maxnl[i] 表示1~i中的区间最大值。
ll minsum[N]; //minsum[i] 表示1~i中的前缀和最小值。
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1 ; i<=n ; i++) cin>>a[i];
        for(int i=1 ; i<=n ; i++) sum[i]=sum[i-1]+a[i];
        for(int i=n ; i>=1 ; i--) maxsum[i]=max(maxsum[i+1],sum[i]);
        for(int i=1 ; i<=n ; i++) minsum[i]=min(minsum[i-1],sum[i]);
        for(int i=n ; i>=1 ; i--)
        {
            maxnr[i]=max(maxnr[i+1],maxsum[i]-sum[i-1]);
        }
        for(int i=1 ; i<=n ; i++)
        {
            maxnl[i]=max(maxnl[i-1],sum[i]-minsum[i]);
        }
        ll ans=0;
        for(int i=1 ; i<n ; i++)
        {
            ans=max(maxnl[i]+maxnr[i+1],ans);
        }
        cout<<ans<<endl;
    }
    return 0;
}

总结
另外,维护 i 右边的所有子区间的和的最大值还有一种办法,这是使用的动态规划的思想——用f[i]表示必须要选i的情况下i向右最大的区间和, f[i]=max(a[i],a[i]+f[i+1]),然后maxn[i]=max(f[i],maxn[i+1])。

二:区间数目变多——找 m个长度为 k 的不相交区间使得他们的权值和最大 ( 1≤n≤5000)
三:区间数目变多且不限制长度——找 m 个不相交长度不限的区间使得他们权值和最大( 1≤n≤5000)
变形二和变形三真的不会,题解都看不懂,等以后再来补吧。
https://ac.nowcoder.com/discuss/392146

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值