寒假集训做题分享(3)
2024/1/20,集训接近一周了,昨晚休息的比较好今天稍微有点精力做题了,明天就可以歇周末了,开心
OK,接下来是今天上午的题目分享。
P1714 切蛋糕
我也想吃蛋糕啊。。。
题目大意是给出 \(n\)块蛋糕,和最多能吃的蛋糕数\(m\),从中找出连续的\(k\)块蛋糕使得这些蛋糕加起来的幸运值最高(\(1\) <= $ k $ <= $ m $)。
这道题用到了前缀和和队列,很简单的我们能够想到暴力的做法,时间复杂度\(O(N^2)\)。在此题中可以过掉绝大多数测试点,但是如果想要AC那么就需要使用队列了,队列的时间复杂度\(O(N)\)。
下面先是暴力做法的代码:
#include<bits/stdc++.h>
using namespace std;
// 定义结束符为换行符
#define endl '\n'
// 定义int为长整型
#define int long long
// 定义常量N,表示数组的最大长度
const int N = 1e8 + 10;
// 定义常量M,但在这段代码中并未使用到M
const int M = 1010;
// 初始化maxx为-1e18,表示当前最大值的初始值
int maxx = -1e18;
// 初始化minn为1e18,但在这段代码中并未使用到minn
int minn = 1e18;
// 初始化cnt和q、a数组,但在这段代码中并未使用到cnt和q数组
int cnt;
int q[N], a[N];
signed main() {
// 从标准输入读取两个整数n和m
int n, m;
cin >> n >> m;
int i, j; // 定义并初始化i和j,用作循环计数器
for (i = 1; i <= n; i++) { // 循环读取数组元素并计算累计和
// 从标准输入读取一个long long类型的数并存储到a[i]中
scanf("%lld", &a[i]);
// 计算累计和并存储到q[i]中
q[i] = q[i - 1] + a[i];
}
for (i = 0; i <= n; i++) { // 外层循环遍历所有可能的窗口起始点
for (j = i + 1; j <= i + m; j++) { // 内层循环遍历每个窗口的长度
// 如果当前窗口的最大值大于maxx,则更新maxx的值
if (q[j] - q[i] > maxx)
maxx = q[j] - q[i];
}
}
// 输出当前窗口的最大值并换行
cout << maxx << endl;
return 0; // 主函数结束,返回0表示程序正常退出
}
注意:我们不一定会取\(m\)块蛋糕,\(1\) 到 \(m\) 都是可以的,做题时应当注意。
接下来是队列+前缀和做法:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int N = 1e8 + 10; // 定义常量 N,表示数组的最大长度
const int M = 1010; // 定义常量 M,但代码中并未使用到 M
int maxx = -1e18; // 定义并初始化 maxx,表示当前滑动窗口中的最大值
int minn = 1e18; // 定义并初始化 minn,但代码中并未使用到 minn
int cnt;
int q[N], a[N]; // 定义数组 q 和 a,用于存储计算出的累计和和原数组
deque<int>de; // 定义双端队列 de,用于维护滑动窗口的边界
signed main() {
int n, m; // 定义并初始化 n 和 m,分别表示数组的长度和滑动窗口的大小
cin >> n >> m; // 从标准输入读取 n 和 m 的值
int i, j; // 定义并初始化 i 和 j,用作循环计数器
for (i = 1; i <= n; i++) { // 循环读取数组元素并计算累计和
scanf("%lld", &a[i]); // 从标准输入读取一个 long long 类型的数并存储到 a[i] 中
q[i] = q[i - 1] + a[i]; // 计算累计和并存储到 q[i] 中
}
de.push_back(0); // 将窗口的左边界设置为 0
for (i = 1; i <= n; i++) { // 循环处理每个元素
while (de.front() + m < i) { // 如果窗口的左边界超出了窗口范围,则移除左边界元素
de.pop_front();
}
maxx = max(maxx, q[i] - q[de.front()]); // 更新当前窗口的最大值
while (!de.empty() && q[de.back()] >= q[i]) { // 如果窗口的右边界不是当前最大值,则移除右边界元素
de.pop_back();
}
de.push_back(i); // 将当前元素设置为窗口的右边界
}
cout << maxx << endl; // 输出当前窗口的最大值并换行
}