最大子段和
- 方法1:处理当前位置之前的前缀和的最小值,每次计算当前位置到这个位置的子段和即可
代码:1
2
3
4
5
6
7
8
9
10
11
12
13const ll inf=1e9+1;
void solve(){
ll n; cin>>n;
vector<ll> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
ll minn=0,now=0,ans=-inf;
for(int i=1;i<=n;i++){
now+=a[i];
ans=max(ans,now-minn);
minn=min(minn,now);
}
cout<<ans<<endl;
}
注意几个细节,首先minn存储的是到目前为止的最小值,应该默认为0,在所有数字全为正数的情况下,表示空串的前缀和为0.先计算ans再计算minn,这是因为不能产生空串,保证取的是前面的前缀和.
- 方法2:传统
dp法:
代码:1
2
3
4
5
6
7
8
9
10
11
12
using namespace std;
int main(){
long long a,maxn=LONG_LONG_MIN,sum=0,n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a; sum+=a;
if(sum<a) sum=a;
if(sum>maxn) maxn=sum;
}
cout<<maxn<<endl;
}
思路:如果当前值比前面求的和还要大,那么放弃前面的求和,直接新开一段
变形:求子段%p意义下的最大子段和
依旧先计算前缀和(在%p意义下),前面的前缀和更小,可能是两个和还没相差p,要是当前的更小,大概率是超过了p,翻上去了,所以要考虑两个位置,前缀最小值和第一个比当前数字大的前缀和值.
代码略,自己写去,up懒
https://zestfulyk.github.io/ZestfulYK-blog/2025/02/12/%E6%9C%80%E5%A4%A7%E5%AD%90%E6%AE%B5%E5%92%8C/
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 ZestfulYK的Blog!