最大连续区间和问题

最大连续区间和是一个经典的问题.

给定一个长度为 n n n的序列 a [ 1 ] , a [ 2 ] . . . a [ n − 1 ] , a [ n ] a[1],a[2]...a[n-1],a[n] a[1],a[2]...a[n1],a[n],求一个连续的子序列 a [ i ] , a [ i + 1 ] . . . a [ j − 1 ] , a [ j ] , a[i],a[i+1]...a[j-1],a[j], a[i],a[i+1]...a[j1],a[j]使得 a [ i ] + a [ i + 1 ] . . . a [ j − 1 ] + a [ j ] a[i]+a[i+1]...a[j-1]+a[j] a[i]+a[i+1]...a[j1]+a[j]最大。
暴力做法:枚举每个子段, 时间复杂度为O(n2)
for(int i=1;i<=n;i++){
	for(int j=1;j<=i;j++){
		ans = max(ans,sum[i]-sum[j-1]);
	}
}
优化1: a n s = m a x ( s u m [ i ] − m i n { s u m [ j ] } ) , ans = max(sum[i] - min \left\{ sum[j] \}\right), ans=max(sum[i]min{sum[j]}), ( 0 < = j < i < = n ) (0<=j<i<=n) (0<=j<i<=n)

而最小前缀和可以动态维护,所以时间复杂度为O(n)

for(int i=1;i<=n;i++){
    ans = max(ans,sum[i]-minn);
    minn = min(minn,sum[i]);
}
优化2:dp优化,时间复杂度为O(n)

f [ i ] : f[i]: f[i]: a [ i ] a[i] a[i] 结尾的最大连续区间和
f [ i ] = m a x ( 0 , f [ i − 1 ] ) + a [ i ] f[i] = max(0,f[i-1])+a[i] f[i]=max(0,f[i1])+a[i]

for(int i=1;i<=n;i++){
	f[i] = max(0, f[i-1]) + a[i];
	ans = max(ans,f[i]);
}


cf edu123 C. Increase Subarray Sums

问题:在数字串中,每次在不重复的数上加0 ~ n个x,每次加x都是独立的,并且求每次最大的子串和。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
 
const int N = 5005;
int f[N][N];//f[i][j]表示以i结尾的、给j个元素添加x后的最大连续数组和
 
void solve(){
    int n,x;
    cin>>n>>x;
    for(int i=0;i<=n;i++){
        for(int j=0;j<=n;j++){
            f[i][j]=0;
        }
    }
    for(int i=1;i<=n;i++){
        int a;
        cin>>a;
        
        f[i][0] = max(f[i-1][0],0) + a;
        
        for(int j=1;j<=n;j++){
            // int v1 = max(f[i-1][j], 0) + a;//不加x
            // int v2 = max(f[i-1][j-1], 0) + a + x;//加x
            // f[i][j] = max(v1, v2);
            f[i][j] = max(f[i-1][j-1], 0) + a + x;
        }
    }
    for(int i=0;i<=n;i++){
        int res = 0;
        for(int j=1;j<=n;j++){
            res = max(res, f[j][i]);
        }
        cout<<res<<" ";
    }
    cout<<endl;
}
 
int main(){
    int T;
    T=1;
    cin>>T;
    while(T--) solve();
    return 0;
}

cf edu69 D. Yet Another Subarray Problem
求 ∑ i = l r ( a i − k ∗ ⌈ r − l + 1 m ⌉ ) 的 最 大 值 求 \sum\limits_{i=l}^r (a_i-k*\left\lceil\dfrac{r-l+1}{m}\right\rceil)的最大值 i=lr(aikmrl+1)

( 1 ≤ n ≤ 3 ⋅ 1 0 5 , 1 ≤ m ≤ 10 , 1 ≤ k ≤ 1 0 9 ) , ( − 1 0 9 ≤ a i ≤ 1 0 9 ) . (1≤n≤3⋅10^5,1≤m≤10,1≤k≤10^9),(−10^9≤ai≤10^9). (1n3105,1m10,1k109),(109ai109).

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 1e18
const int N=3e5+5;

//每m个数都会减一个k
ll f[N][20];//dp[i][j],表示以i为右端点,长度为%m=j的区间最大值。
ll a[N];

int main(){
    ll n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    
    for(int i=0;i<=n;i++){
        for(int j=0;j<=m-1;j++) f[i][j] = -inf;
    }
    
    ll ans = 0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m-1;j++){
            if(j==1 || m==1) f[i][j] = max(f[i-1][0]-k,-k)+a[i];
            else if(j==0) f[i][j] = f[i-1][m-1]+a[i];
            else f[i][j] = f[i-1][j-1]+a[i];
            ans = max(ans,f[i][j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值