寒假集训做题分享(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; // 输出当前窗口的最大值并换行  
}

我对于队列的使用不太熟悉,有部分代码还是参考了一下。唉,我太菜了

posted @ 2024-07-05 17:38  ZhangDT  阅读(0)  评论(0编辑  收藏  举报