第十四届蓝桥杯省赛C++C组——子矩阵(蓝桥杯篇章完结撒花)

本来想写的速成日志也没写多少,cb国二,最后一题树形DP调了一小时发现h数组没置 -1,最后无果,如果没马虎可能有国一水平了,正儿八经准备用了两个月,因为要考研,每天只学2 - 3小时的算法,一共刷了300多道题吧,由于之前选过ACM(实验课因为周六去,懒得去还给我挂了)和算法分析课,所以还是有点基础的,如果算上一年前刷的题总共加起来也就400多道题吧。

说一下历程吧,一年前的题都是老师布置的作业,迫不得已做的,不过对算法有了个大概的了解,算是入门;省赛之前做的洛谷热度最高的题单,做了大概170 180道题,省一排名比较靠后;省赛之后想了想还是准备一下吧,跟着y总的ACWing的蓝桥杯辅导课和每日一题大概做了80道题,期间穿插的刷了刷洛谷的同类型题,一共大概130 140道题。

本想搞个速成日志的,不过我发现速成不适合搞日志,只有那些长时间刷题打ACM的大佬,刷题刷到瓶颈写写日志博客才有用,像我这种速成的,刷题都来不及更别说写博客了。。
不说了,明天考6级,对于考研党来说6级的成绩还是很重要的,祝大家都能得偿所愿未来都能上岸。*
完结撒花❀


单调队列

在这里插入图片描述

只要使用单调队列分别维护行和列,就可以了
如果不明白什么是单调队列,可以看一下这个题
P1886 滑动窗口 /【模板】单调队列
该题和P2216 [HAOI2007]理想的正方形十分相似,只是多了一个模运算,但恰恰这个模运算,卡了我1个多小时。。。

#include <bits/stdc++.h>
//这个题一度让我以为代码某处的逻辑有误,但是使用该代码可以AC理想的正方形,于是就一直在研究细节。。一个模运算卡了我一个小时。。
using namespace std;
#define ll long long
const int N = 1005;
const int mod = 998244353;
int n,m,a,b,ans,g[N][N],mm[N][N],MM[N][N];
int minr[N][N],minc[N][N],maxr[N][N],maxc[N][N];

void monotonic_row(){
    memset(mm,0,sizeof mm);
    memset(MM,0,sizeof MM);

    for(int i = 1; i <= n; i ++ ){

        int head_min=1,last_min=0;
        int head_max=1,last_max=0;
        int p_min[N],p_max[N];
        for(int j = 1; j <= m; j ++ ){
            while(head_min <= last_min && g[i][j] <= mm[i][last_min]){
                last_min--;
            }
            while(head_max <= last_max && g[i][j] >= MM[i][last_max]){
                last_max--;
            }
            mm[i][++ last_min] = g[i][j];
            p_min[last_min] = j;
            MM[i][++ last_max] = g[i][j];
            p_max[last_max] = j;

            while(p_min[head_min] <= j - b){
                head_min ++ ;
            }
            while(p_max[head_max] <= j - b){
                head_max ++ ;
            }
            if(j >= b) minr[i][j] = mm[i][head_min] ,maxr[i][j] = MM[i][head_max];
        }
    }
}

void monotonic_colum(){
    memset(mm,0,sizeof mm);
    memset(MM,0,sizeof MM);

    for(int i = 1; i <= m; i ++ ){

        int head_min=1,last_min=0;
        int head_max=1,last_max=0;
        int p_min[N],p_max[N];

        for(int j = 1; j <= n; j ++ ){
            while(head_min <= last_min && minr[j][i] <= mm[last_min][i]){
                last_min--;
            }
            while(head_max <= last_max && maxr[j][i] >= MM[last_max][i]){
                last_max--;
            }

            mm[++ last_min][i] = minr[j][i];
            p_min[last_min] = j;
            MM[++ last_max][i] = maxr[j][i];
            p_max[last_max] = j;

            while(p_min[head_min] <= j - a){
                head_min ++ ;
            }
            while(p_max[head_max] <= j - a){
                head_max ++ ;
            }
            if(j >= a) minc[j][i] = mm[head_min][i] ,maxc[j][i] = MM[head_max][i];
        }
    }
}

int main()
{
    scanf("%d%d%d%d", &n, &m, &a, &b);
    for(int i = 1; i <= n; i ++ ){
        for(int j = 1;j <= m; j ++ ){
            scanf("%d", &g[i][j]);
        }
    }
    monotonic_row();
    monotonic_colum();


    for(int i = a; i <= n; i ++ ){
        for(int j = b ; j <= m ; j ++ ){
//            ans= ( ans +  ( minc[i][j] % mod ) * ( maxc[i][j] % mod ) ) % mod;//错误的,虽然两个数都模上mod,但是两数相乘的结果仍然可能超过int范围,导致结果错误
//            ans= ( ans +  ( ( minc[i][j] % mod ) * ( maxc[i][j] % mod ) ) % mod ) % mod;//错误的,同上,对已经越界的数进行模运算,得到的结果仍然是错误的
            ans= ( ans +  ( (ll) minc[i][j] * maxc[i][j] ) ) % mod;//正确的
        }
    }
    printf("%d",ans);
    return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值