最大子序和

输入一个长度为 <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">1n,m3000001≤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 }

 

posted @ 2022-09-12 19:37  Luli&  阅读(26)  评论(0)    收藏  举报