2023第14届蓝桥杯C组C++题解(持续更新中...)
目录
试题 A: 求和
试题 F: 子矩阵
试题 A: 求和
本题总分:5 分
【问题描述】 求 1 (含)至 20230408 (含)中每个数的和。
【答案提交】 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
签到题:
#include<iostream>
using namespace std;
int main()
{long long ans = 0; for(int i = 1; i <= 20230408; i ++)ans += i;cout << ans;return 0;
}
试题 F: 子矩阵
时间限制: 2.0s 内存限制: 256.0MB
本题总分:15 分
【问题描述】 给定一个 n × m (n 行 m 列)的矩阵。 设一个矩阵的价值为其所有数中的最大值和最小值的乘积。求给定矩阵的 所有大小为 a × b (a 行 b 列)的子矩阵的价值的和。 答案可能很大,你只需要输出答案对 998244353 取模后的结果。
【输入格式】 输入的第一行包含四个整数分别表示 n, m, a, b ,相邻整数之间使用一个空 格分隔。 接下来 n 行每行包含 m 个整数,相邻整数之间使用一个空格分隔,表示矩 阵中的每个数 Ai, j 。
【输出格式】 输出一行包含一个整数表示答案。
【样例输入】 2 3 1 2 1 2 3 4 5 6
【样例输出】 58
【样例说明】 1 × 2 + 2 × 3 + 4 × 5 + 5 × 6 = 58 。
【评测用例规模与约定】 对于 40% 的评测用例,1 ≤ n, m ≤ 100 ; 对于 70% 的评测用例,1 ≤ n, m ≤ 500 ; 对于所有评测用例,1 ≤ a ≤ n ≤ 1000 1 ≤ b ≤ m ≤ 1000 1 ≤ Ai, j ≤ 109 。
考点:单调队列维护二维滑动窗口
目标是在给定的二维数组中找到所有大小为 a x b 的子矩阵中最小值和最大值的乘积的最大值。
该代码使用滑动窗口技术高效地计算所有大小为 a x b 的子矩阵的最大值和最小值。
该算法的主要思想是,首先使用滑动窗口技术计算二维数组中每行长度为 b 的所有子数组的最大值和最小值。然后,我们可以使用这些值来计算每个子矩阵的大小为 a x b 的最大值和最小值,通过计算子矩阵中每列长度为 a 的所有子数组的最大值和最小值来实现。
该算法使用两个辅助的二维数组
maxx
和minx
来存储在原始二维数组中以位置 (i,j) 结尾的所有大小为 a x b 的子矩阵的最大值和最小值。这些值使用上面描述的滑动窗口技术计算得出。最终答案是所有大小为 a x b 的子矩阵中最小值和最大值的乘积的最大值之和。
以下是带有一些注释的代码,用于解释算法的不同部分:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1010;
const int mod = 998244353;int w[N][N];
int ma[N][N],mi[N][N];
int maxx[N][N],minx[N][N];
int q[N];int main()
{int n,m,a,b;cin >> n >> m >> a >> b;for(int i = 1; i <= n; i ++ )for(int j = 1; j <= m; j ++ )cin >> w[i][j];int hh = 0, tt = -1;memset(ma, -0x3f3f3f3f, sizeof ma);memset(mi, 0x3f3f3f3f, sizeof mi);//求横向滑动窗口 最大值for(int i = 1; i <= n; i ++ ){hh = 0,tt = -1;for(int j = 1; j <= m; j ++ ){if( j - b + 1 > q[hh] ) hh ++;while( w[i][q[tt]] <= w[i][j] && hh <= tt ) tt --;q[ ++ tt ] = j;if(j >= b) ma[i][j] = w[i][q[hh]];}}//求横向滑动窗口 最小值for(int i = 1; i <= n; i ++ ){hh = 0,tt = -1;for(int j = 1; j <= m; j ++ ){if( j - b + 1 > q[hh] ) hh ++;while( w[i][q[tt]] >= w[i][j] && hh <= tt ) tt --;q[ ++ tt ] = j;if(j >= b) mi[i][j] = w[i][q[hh]];}}//在横向的最值基础上求出纵向的最值 就是当前二维窗口的最值//纵向最大值for(int j = 1; j <= m; j ++ ){hh = 0,tt = -1;for(int i = 1; i <= n; i ++ ){if(i - a + 1 > q[hh]) hh ++;while(hh <= tt && ma[q[tt]][j] <= ma[i][j]) tt --;q[ ++ tt ] = i;if(i >= a && j >= b) maxx[i][j] = ma[q[hh]][j];}}//纵向最小值 for(int j = 1; j <= m; j ++ ){hh = 0,tt = -1;for(int i = 1; i <= n; i ++ ){if(i - a + 1 > q[hh]) hh ++;while(hh <= tt && mi[q[tt]][j] >= mi[i][j]) tt --;q[ ++ tt ] = i;if(i >= a && j >= b) minx[i][j] = mi[q[hh]][j];}}LL ans = 0;for(int i = a; i <= n; i ++ )for(int j = b; j <= m; j ++ ){ans += ((LL) maxx[i][j] * minx[i][j]) % mod;}printf("%lld",ans % mod);return 0;
}
该算法的时间复杂度为 O(nm),其中 n 和 m 分别是原始二维数组的行数和列数。
(陆续更新ing..........)