一道很有意思的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; }