一道很有意思的dp,说它有意思是因为他的原理其实很简单,而且扫描一次就可以得到最终的答案。
如果当前这个数之前的和小于0,那么最大和就从当前的数重新开始;否则最大和就是之前的和加上当前这个数。
这样为什么是正确的呢? 我们假设当前这个数之前的连续和小于0,那么他对下面的贡献是负的,所以无论后面的数有多大,最大连续和肯定都不如舍弃前面负贡献的和大。
然后每次更新dp[i]的最大值,就相当于由枚举的连续和的终点。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int T,n,a[100005],dp[100005];
int main(){
scanf("%d",&T);
int kase = 0;
while(T--){
scanf("%d",&n);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
printf("Case %d:\n",++kase);
int ans = -1000000000,x1,x2,l,r;
dp[1] = a[1];
x1 = 1; ans = dp[1];
l=1; r=1;
for(int i=2;i<=n;i++){
if(dp[i-1]<0) {
x1 = i;
dp[i] = a[i];
} else dp[i] = dp[i-1] + a[i];
if(ans<dp[i]){
ans = dp[i];
l = x1; r = i;
}
}
printf("%d %d %d\n",ans,l,r);
if(T) printf("\n");
}
return 0;
}