最大子序和
输入一个长度为 <span id="MathJax-Span-2" class="mrow"><span id="MathJax-Span-3" class="mi">nn 的整数序列,从中找出一段长度不超过 <span id="MathJax-Span-5" class="mrow"><span id="MathJax-Span-6" class="mi">mm 的连续子序列,使得子序列中所有数的和最大。
注意: 子序列的长度至少是 <span id="MathJax-Span-8" class="mrow"><span id="MathJax-Span-9" class="mn">11。
输入格式
第一行输入两个整数 <span id="MathJax-Span-11" class="mrow"><span id="MathJax-Span-12" class="mi">n,mn,m。
第二行输入 <span id="MathJax-Span-16" class="mrow"><span id="MathJax-Span-17" class="mi">nn 个数,代表长度为 <span id="MathJax-Span-19" class="mrow"><span id="MathJax-Span-20" class="mi">nn 的整数序列。
同一行数之间用空格隔开。
输出格式
输出一个整数,代表该序列的最大子序和。
数据范围
<span id="MathJax-Span-22" class="mrow"><span id="MathJax-Span-23" class="mn">1≤n,m≤3000001≤n,m≤300000
输入样例:
6 4
1 -3 5 1 -2 3
输出样例:
7
竟然可以用到之前学到ST表
理解:
该题的含义是求区间和最大,在有约束条件的情况下。既然是区间和,那我们一定可以用前缀和来进行优化了。那问题就转化为了在右端点确定的情况下求区间最大和(右端点确定,左端点也就确定了,为[i - m, i -1],注意i-m小于0的情况。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 3e5 + 10; 6 int f[N], dp[N][30]; 7 void st_prework(int *a, int n) 8 { 9 for(int i = 1; i <= n; i ++) dp[i][0] = a[i]; 10 int k; 11 k = (int)log2(n); //(int)log2(n)是向下取整,所以不会超过数组个数 12 13 for(int j = 1; j <= k; j ++) //j 是枚举的右端点 14 { 15 for(int i = 1; i + (1 << j) - 1<= n; i ++) //因为我们是以jdp[i][j],所以要满足i + (1 << j) - 1<= n 16 { 17 dp[i][j] = min(dp[i][j-1], dp[i + (1 << (j - 1))][j - 1]); // #求最小值 18 // dp[i][j] = max(dp[i][j-1], dp[i + (1 << (j - 1))][j - 1]) ;//我们在求j的时候实际上是运用j-1进行求解的 19 } 20 } 21 } 22 23 int st_query(int l, int r) 24 { 25 int k; 26 k = (int)log2(r - l + 1); //k表示的是l后有2^k个数,因为该函数默认向下取整, 所以 l + 2^k - 1不会大于 r; 27 return min(dp[l][k], dp[r - (1 << k) + 1][k]); //求最小的 28 // return max(dp[l][k], dp[r - (1 << k) + 1][k]); // 为什么i是(r - (1 << k) + 1),因为 l + 2^k - 1一定 <= r,而(r - (1 << k) + 1) >= l, 且(r - (1 << k) + 1) + 2^k = dp[r][1],为查询区间的末尾 29 } 30 int main() 31 { 32 int n, m; 33 cin >> n >> m; 34 for(int i = 1; i <= n; i ++) 35 { 36 cin >> f[i]; 37 f[i] += f[i-1]; 38 } 39 st_prework(f, n); 40 int ans = f[1]; 41 for(int i = 2; i <= n; i ++) 42 { 43 int j = i - m ; 44 if(j < 1) j = 1; 45 if(i == 1) j = 0; 46 ans = max(ans, f[i] - st_query(j, i - 1)); 47 if(i <= m) ans = max(ans, f[i]); 48 49 } 50 cout << ans << endl; 51 return 0; 52 }
另一种:单调队列
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 const int N = 3e5 + 10; 5 int f[N], q[N]; 6 int main() 7 { 8 int n, m; 9 cin >> n >> m; 10 for(int i = 1; i <= n; i ++) 11 { 12 cin >> f[i]; 13 f[i] += f[i-1]; 14 } 15 int res = INT_MIN; 16 int h, t; 17 h = 0, t = 0; 18 for(int i = 1; i <= n; i++) 19 { 20 if(i - q[h] > m) h++; 21 res = max(res, f[i] - f[q[h]]); 22 while(h <= t && f[q[t]] >= f[i]) t--; 23 q[++t] = i; 24 } 25 cout << res << endl; 26 return 0; 27 }

浙公网安备 33010602011771号