最大连续区间和是一个经典的问题.
给定一个长度为 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[n−1],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[j−1],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[j−1]+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[i−1])+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=l∑r(ai−k∗⌈mr−l+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). (1≤n≤3⋅105,1≤m≤10,1≤k≤109),(−109≤ai≤109).
#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;
}