2023第14届蓝桥杯C组C++题解(持续更新中...)

目录

试题 A: 求和 

试题 F: 子矩阵


试题 A: 求和 

 本题总分:5 分

【问题描述】 求 1 (含)至 20230408 (含)中每个数的和。

【答案提交】 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

签到题:

#include
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 的所有子数组的最大值和最小值来实现。

该算法使用两个辅助的二维数组 maxxminx 来存储在原始二维数组中以位置 (i,j) 结尾的所有大小为 a x b 的子矩阵的最大值和最小值。这些值使用上面描述的滑动窗口技术计算得出。

最终答案是所有大小为 a x b 的子矩阵中最小值和最大值的乘积的最大值之和。

以下是带有一些注释的代码,用于解释算法的不同部分: 

#include 
#include 
#include 
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..........) 

你可能感兴趣的:(蓝桥杯,c++,c语言,算法)