最大子序列和 HDOJ 1003 Max Sum
题意:求MCS(最大连续子序列和)及两个端点
分析:第一种办法:dp[i] = max (dp[i-1] + a[i], a[i]) 可以不开数组,用一个sum表示前i个数字的MCS,其实是一样的。。。类似DP的做法有个名字叫联机算法。
第二种办法:一个前缀记录前i个数字的和,那么ans = sum - mn; mn表示前j个和且和最小
两种办法都是O (n) 1003就这么难?? 推荐学习资料:六种姿势拿下连续子序列最大和问题 最大子序列和问题
收获:MCS问题的两种o (n) 的算法,且还有递归的解法 O (nlogn)
代码1:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1e6 + 10; const int INF = 0x3f3f3f3f; int a[N]; //O (n) void MCS(int n) { int l = 0, ll = 0, rr = 0; int sum = -INF, mx = -INF; for (int i=1; i<=n; ++i) { if (sum + a[i] < a[i]) { sum = a[i]; l = i; } else sum += a[i]; if (sum > mx) { mx = sum; ll = l, rr = i; } } printf ("%d %d %d ", mx, ll, rr); } int main(void) { int T, cas = 0; scanf ("%d", &T); while (T--) { int n; scanf ("%d", &n); for (int i=1; i<=n; ++i) scanf ("%d", &a[i]); printf ("Case %d: ", ++cas); MCS (n); if (T) puts (""); } return 0; }
代码2:
//O (n) //another void MCS(int n) { int l = 0, ll = 0, rr = 0; int sum = 0, mx = -INF, mn = 0; for (int i=1; i<=n; ++i) { sum += a[i]; if (sum - mn > mx) { mx = sum - mn; ll = l; rr = i; } if (sum < mn) { mn = sum; l = i; } } printf ("%d %d %d ", mx, ll + 1, rr); }