当前位置:   article > 正文

蓝桥杯23年第十四届省赛-子矩阵 |暴力、滑动窗口单调队列

蓝桥杯23年第十四届省赛-子矩阵 |暴力、滑动窗口单调队列

题目链接:

蓝桥杯2023年第十四届省赛真题-子矩阵 - C语言网 (dotcpp.com)

6.子矩阵 - 蓝桥云课 (lanqiao.cn)

说明:

单调队列、滑动窗口模板。 先求每行的滑动窗口(最大值和最小值都求),再对求出来的滑动窗口再求每列的。 参考学习链接:https://blog.csdn.net/weixin_72060925/article/details/127952750

对于固定大小的子矩阵, 又是求子矩阵里的最值,那么就要考虑用滑动窗口来做,因为子矩阵大小固定,即行和列大小固定,滑动窗口大小也是在窗口大小固定时使用的。

可以想象一下一个子矩阵,先求每行的滑动窗口(最大值和最小值都求),那么这个子矩阵每行(共a行)的b个(列)元素,都变成一个最值表示,a*b个变成了a个,再对求出来的滑动窗口再求每列的滑动窗口,就是这a行上面的a个元素变成一个最值,也就是一个子矩阵“浓缩”成了一个最值。

如果大小不确定的子矩阵问题,且涉及的是子矩阵的元素和,就要考虑前缀和降维。

代码:

正解:

  1. #include<bits/stdc++.h>
  2. #define int long long
  3. #define endl '\n'
  4. using namespace std;
  5. const int N=1e3+10;
  6. int ans=0;
  7. int mod=998244353;
  8. int g[N][N];
  9. int q[N];
  10. int line_max[N][N];int line_min[N][N];
  11. int minv[N][N];int maxv[N][N];
  12. //四重循环暴力
  13. signed main() {
  14. ios::sync_with_stdio(0);
  15. cin.tie(0);
  16. cout.tie(0);
  17. int n,m,a,b;
  18. cin>>n>>m>>a>>b;
  19. for(int i=0;i<n;i++){
  20. for(int j=0;j<m;j++)
  21. cin>>g[i][j];
  22. }
  23. //每行求滑动窗口 对该行的某个起点(j)求出窗口里的最大值
  24. for(int i=0;i<n;i++){
  25. int h=0,t=-1;//注意h和t写在第一层里 ,每行的滑动窗口不相关
  26. for(int j=0;j<m;j++){
  27. if(h<=t&&q[h]<j-b+1){
  28. h++;
  29. }
  30. while(h<=t&&g[i][q[t]]<=g[i][j]){
  31. t--;
  32. }
  33. q[++t]=j;
  34. if(j-b+1>=0) line_max[i][j-b+1]=g[i][q[h]];
  35. }
  36. }
  37. //每行求滑动窗口 对该行的某个起点(j)求出窗口里的最小值
  38. for(int i=0;i<n;i++){
  39. int h=0,t=-1;//注意h和t写在第一层里 ,每行的滑动窗口不相关
  40. for(int j=0;j<m;j++){
  41. if(h<=t&&q[h]<j-b+1){
  42. h++;
  43. }
  44. while(h<=t&&g[i][q[t]]>=g[i][j]){
  45. t--;
  46. }
  47. q[++t]=j;
  48. if(j-b+1>=0) line_min[i][j-b+1]=g[i][q[h]];
  49. }
  50. }
  51. //对已经求出的行滑动窗口(每行的每个窗口变成由最大值代表的一个数)最大值矩阵 求每列的滑动窗口最大值
  52. for(int j=0;j<m-b+1;j++){
  53. int h=0,t=-1;
  54. for(int i=0;i<n;i++){
  55. if(h<=t&&q[h]<i-a+1)
  56. h++;
  57. while(h<=t&&line_max[q[t]][j]<=line_max[i][j])
  58. t--;
  59. q[++t]=i;
  60. //第j列上的 第i-a+1个窗口 保存对应最大值
  61. if(i-a+1>=0) maxv[i-a+1][j]=line_max[q[h]][j];
  62. }
  63. }
  64. for(int j=0;j<m-b+1;j++){
  65. int h=0,t=-1;
  66. for(int i=0;i<n;i++){
  67. if(h<=t&&q[h]<i-a+1)
  68. h++;
  69. while(h<=t&&line_min[q[t]][j]>=line_min[i][j])
  70. t--;
  71. q[++t]=i;
  72. //第j列上的 第i-a+1个窗口 保存对应最大值
  73. if(i-a+1>=0) minv[i-a+1][j]=line_min[q[h]][j];
  74. }
  75. }
  76. for(int i=0;i<n-a+1;i++){
  77. for(int j=0;j<m-b+1;j++){
  78. ans=(ans+minv[i][j]*maxv[i][j]%mod)%mod;
  79. }
  80. }
  81. cout<<ans;
  82. return 0;
  83. }

暴力(70%蓝桥官网测试点):

  1. #include<bits/stdc++.h>
  2. #define int long long
  3. #define endl '\n'
  4. using namespace std;
  5. const int N=1e3+10;
  6. int ans=0;
  7. int mod=998244353;
  8. int g[N][N];
  9. //四重循环暴力
  10. signed main() {
  11. ios::sync_with_stdio(0);
  12. cin.tie(0);
  13. cout.tie(0);
  14. int n,m,a,b;
  15. cin>>n>>m>>a>>b;
  16. for(int i=0;i<n;i++){
  17. for(int j=0;j<m;j++)
  18. cin>>g[i][j];
  19. }
  20. for(int i=0;i<n-a+1;i++){
  21. for(int j=0;j<m-b+1;j++){
  22. int mx=0,mn=1e9;
  23. for(int k=0;k<a;k++){
  24. for(int l=0;l<b;l++){
  25. mx=max(mx,g[i+k][j+l]);
  26. mn=min(mn,g[i+k][j+l]);
  27. }
  28. }
  29. ans=(ans+mx*mn%mod)%mod;
  30. }
  31. }
  32. cout<<ans;
  33. return 0;
  34. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/374295
推荐阅读
相关标签
  

闽ICP备14008679号