专栏文章

题解:P13889 [蓝桥杯 2023 省 Python A] 子矩阵

P13889题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minint1i
此快照首次捕获于
2025/12/02 03:02
3 个月前
此快照最后确认于
2025/12/02 03:02
3 个月前
查看原文

总述

题目需要让我们求出在nmn*m的矩阵里每个大小为aba*b的子矩阵最大值最小值乘积的和。
对于数据范围,仅仅3秒,暴力枚举求和显然不够(时间复杂度为O(nmab)O(nmab),对于全数据就是101210^{12})。这个时候我们需要想办法优化。
我们发现,这个nmn*m的矩阵是不会有任何数被修改的。也就是说,我们可以采用离线的做法预处理每一个子矩阵的两个最值。对于这种RMQ问题,我们通常会使用单调队列和st表解决。考虑到时间复杂度在使用单调队列的情况下能够达到最优,我就单独讲述单调队列做法。(二位数列做单调队列能达到约O(nm)O(nm),而st表在时间和空间上会较大,需要额外优化)

前置

先说一下一维数组的单调队列,可先去单调队列模板看一看,稍微了解一番。
我们会发现,在长为kk的区间里,枚举去比较会让除了开头k1k-1和末尾k1k-1的数以外的所有数都参与比较多次,无用的枚举占据的多部分时间。
我们既然需要在连续的kk个数中求出最值,我们不妨使用一个双端队列实时更新最值。显然,当我们求最大值的时候,若一个数字从序列添加到队列末尾,并且这个数要比队前的数要大,那么前面的数就失去了在这一段区间里竞争最大值的资格,可以直接弹出队列。求最小值也是同理。
考虑到区间长度为kk,于是在当前数字下标ii和队头q.front()q.front()满足下列关系时,该队头就不属于此区间,需要弹出。
iq.front()+1>ki-q.front()+1>k
这一个队列的核心用处就是求出最值,那么它肯定也保证处于队头的必定时查询区域中的最值。每个数只会入队和出队各一次,完全不会有多余比较,时间复杂度降到了O(n)O(n)

结合上述理论

子矩阵大小aba*b,其实就变相地告诉了我们单调队列需要维护的区间长度。用O(nm)O(nm)的时间枚举矩阵,用两个双端队列维护子区间的最大、最小值,再用两个二维数组同步保存当前iijj列的最大、小值即可。
对于矩阵中每一个数字,其范围为1Ai,j1091\leq A_{i,j} \leq 10^9。需要考虑最小值和最大值都为10910^9,还要乘积的情况,为了防止在mod998244353mod998244353前就超出int范围,我们需要开long long变量保存。另一个,在统计答案总和时,我们需要计算一次取模一次。具体为何,请看下列数据(十分极端的数据)
n=103,m=103,a=b=1,Ai,j=109n=10^3,m=10^3,a=b=1,\forall A_{i,j}=10^9
每个子矩阵可贡献101810^{18},有10610^6个这样的子矩阵,加在一起的总和巨大。所以在计算过程中需要频繁地取模,防止溢出。

评论

0 条评论,欢迎与作者交流。

正在加载评论...