算法学习-单调队列优化系列
P1714 切蛋糕
题目描述
今天是小Z的生日,同学们为他带来了一块蛋糕。这块蛋糕是一个长方体,被用不同色彩分成了n个相同的小块,每小块都有对应的幸运值。
小Z作为寿星,自然希望吃到的蛋糕的幸运值总和最大,但小Z最多又只能吃m小块的蛋糕。
请你帮他从这n小块中找出连续的k块蛋糕,使得其上的总幸运值最大。
形式化地,在数列{p_n}中,找出一个子段[l,r] (r-l+1≤m),最大化∑(i=l to r) p_i。
输入格式
第一行两个整数n,m。分别代表共有n小块蛋糕,小Z最多只能吃m小块。
第二行n个整数,第i个整数p_i代表第i小块蛋糕的幸运值。
输出格式
仅一行一个整数,即小Z能够得到的最大幸运值。
输入输出样例
输入 #1
5 2
1 2 3 4 5
输出 #1
9
输入 #2
6 3
1 -2 3 -4 5 -6
输出 #2
5
说明/提示
数据规模与约定
- 对于20%的数据,有1≤n≤100。
- 对于100%的数据,有1≤n≤5×10^5,|p_i|≤500。
保证答案的绝对值在[0,2^31-1]之内。
解题思路:
转化为找不超过m的连续子序列, 使子序列的元素值和最大->o(nm) 超时....
想到可以维护一个固定长度为m的滑动窗口(单调序列),满足窗口内元素单调递增, 用deque实现 ->o(n) √
算法思路:
对于数组 a[1..n],求长度不超过 m 的最大子数组和。
定义前缀和:
S[i] = Σk=1i a[k],S[0] = 0
则问题可表示为:
max1≤l≤r≤n, r-l+1≤m Σk=lr a[k]
= max1≤i≤n maxi-m≤j≤i-1 (S[i] - S[j])
进一步化简:
maxi-m≤j≤i-1 (S[i] - S[j]) = S[i] - mini-m≤j≤i-1 S[j]
因此,我们只需要用单调队列维护滑动窗口 [i-m, i-1] 中的最小 S[j] 即可。
代码呈现
点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
#include <map>
#include <string>
#include <iomanip>
#include <cmath>
#include <numeric>
#include <climits>
#include <unordered_map>
#include <stack>
#include <utility>
#include <set>
#define ll long long
#define ull unsigned long long
struct node {
ll sum, id, num;
};
const int N = 5e5 + 5;
const int MOD = 998244353;
const ll INF = 1e18;
int n, m;
ll a[N],sum[N];
std::deque<ll> q;
void solve() {
// 维护一个固定长度为m的滑动窗口 满足窗口内元素单调递增
std::cin >> n >> m;
for (int i = 1; i <= n; ++i) std::cin >> a[i];
sum[0] = 0;
for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i];
ll max_val = -INT_MAX;
q.push_back(0);
for (int i = 1; i <= n; ++i) {
if (!q.empty()) {
max_val = std::max(max_val, sum[i] - sum[q.front()]);
}
while (!q.empty() && sum[q.back()]>=sum[i]) {
q.pop_back();
}
q.push_back(i);
if (!q.empty() && q.front() < i - m + 1) {
q.pop_front();
}
}
std::cout << max_val << std::endl;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0); std::cout.tie(0);
int t = 1;
// std::cin >> t; // 多组数据别忘记初始化!!
while (t--) {
solve();
}
return 0;
}
后记:
此为我的第一篇博客,难耐激动之情,于此奉告!

浙公网安备 33010602011771号