【题目大意】

有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

【思路】

裸的二维单调队列。二维单调队列的思路其实很简单:

(1)对于每一行维护两个宽度为n的滑动窗口记录单行中的min和max,和POJ2823一个道理。此时相当于把n个格子浓缩到了一个格子当中。

(2)维护n*n大小的二维滑动窗口中的min和max。由于有了第一步操作,只要考虑每一个n*n的矩形右上角到右下角的最值即可。相当于对于每一列,维护两个宽度为n的滑动窗口。此时循环要行和列里外颠倒,而列只要从第n列开始维护即可(我一开始就错在了这两个地方)

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #define INF 0x7fffffff
  6. struct node
  7. {
  8. int data,pos;
  9. };
  10. using namespace std;
  11. const int MAXN=+;
  12. int a,b,n;
  13. int num[MAXN][MAXN];
  14. int rmin[MAXN][MAXN],rmax[MAXN][MAXN],smin[MAXN][MAXN],smax[MAXN][MAXN];
  15.  
  16. void init()
  17. {
  18. scanf("%d%d%d",&a,&b,&n);
  19. for (int i=;i<a;i++)
  20. for (int j=;j<b;j++) scanf("%d",&num[i][j]);
  21. }
  22.  
  23. void humdrum_queue()
  24. {
  25. /*对于每一行,用单调队列维护[x-n+1,x]的最小值和最大值*/
  26. for (int i=;i<a;i++)
  27. {
  28. int minhead=,mintail=,maxhead=,maxtail=;
  29. node qmin[MAXN],qmax[MAXN];
  30. for (int j=;j<b;j++)
  31. {
  32. int nown=num[i][j];
  33. /*维护最小值*/
  34. while (minhead<mintail && qmin[mintail-].data>nown) mintail--;
  35. qmin[mintail++]=(node){nown,j};
  36. while (minhead<mintail && qmin[minhead].pos<=j-n) minhead++;
  37. rmin[i][j]=qmin[minhead].data;
  38.  
  39. /*维护最大值*/
  40. while (maxhead<maxtail && qmax[maxtail-].data<nown) maxtail--;
  41. qmax[maxtail++]=(node){nown,j};
  42. while (maxhead<maxtail && qmax[maxhead].pos<=j-n) maxhead++;
  43. rmax[i][j]=qmax[maxhead].data;
  44. }
  45. }
  46.  
  47. /*对于以[i,j]为右下角的n*n矩形,用单调队列维护它的最小值和最大值
  48. 这步操作可以用单调队列维护每一列,相当于维护该矩形右上角到右下角对应点的rmin与rmax值*/
  49. /*|ATTENTION|要注意的是这里i和j要颠倒过来,所以内外循环以及队列中的pos均要颠倒!*/
  50. for (int j=n-;j<b;j++)
  51. {
  52. int minhead=,mintail=,maxhead=,maxtail=;
  53. node qmin[MAXN],qmax[MAXN];
  54. for (int i=;i<a;i++)
  55. {
  56. int nowmin=rmin[i][j],nowmax=rmax[i][j];
  57. /*维护最小值*/
  58. while (minhead<mintail && qmin[mintail-].data>nowmin) mintail--;
  59. qmin[mintail++]=(node){nowmin,i};
  60. while (minhead<mintail && qmin[minhead].pos<=i-n) minhead++;
  61. smin[i][j]=qmin[minhead].data;
  62.  
  63. /*维护最大值*/
  64. while (maxhead<maxtail && qmax[maxtail-].data<nowmax) maxtail--;
  65. qmax[maxtail++]=(node){nowmax,i};
  66. while (maxhead<maxtail && qmax[maxhead].pos<=i-n) maxhead++;
  67. smax[i][j]=qmax[maxhead].data;
  68. }
  69. }
  70. }
  71.  
  72. void getans()
  73. {
  74. int ans=INF;
  75. for (int i=n-;i<a;i++)
  76. for (int j=n-;j<b;j++)
  77. if (smax[i][j]-smin[i][j]<ans) ans=smax[i][j]-smin[i][j];
  78. cout<<ans<<endl;
  79. }
  80.  
  81. int main()
  82. {
  83. init();
  84. humdrum_queue();
  85. getans();
  86. return ;
  87. }

【二维单调队列】BZOJ1047-[HAOI2007]理想的正方形的更多相关文章

  1. bzoj1047-理想的正方形(二维单调队列)

    题意: 给一个矩阵,给出行列和每个数,再给出一个N,求出所有N*N的子矩阵中最大值最小值之差的最小值解析: 暴力枚举肯定不行,这题可以用二维单调队列做,把同一行的连续N个点缩成一个点保存最大最小值预处 ...

  2. BZOJ1047: [HAOI2007]理想的正方形 [单调队列]

    1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2857  Solved: 1560[Submit][St ...

  3. bzoj千题计划215:bzoj1047: [HAOI2007]理想的正方形

    http://www.lydsy.com/JudgeOnline/problem.php?id=1047 先用单调队列求出每横着n个最大值 再在里面用单调队列求出每竖着n个的最大值 这样一个位置就代表 ...

  4. [BZOJ1047][HAOI2007]理想的正方形 二维单调队列

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1047 我们对每矩阵的一列维护一个大小为$n$的单调队列,队中元素为矩阵中元素.然后扫描每一 ...

  5. bzoj1047 [HAOI2007]理想的正方形——二维单调队列

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1047 就是先对行做一遍单调队列,再对那个结果按列做一遍单调队列即可. 代码如下: #incl ...

  6. [luoguP2216] [HAOI2007]理想的正方形(二维单调队列)

    传送门 1.先弄个单调队列求出每一行的区间为n的最大值最小值. 2.然后再搞个单调队列求1所求出的结果的区间为n的最大值最小值 3.最后扫一遍就行 懒得画图,自己体会吧. ——代码 #include ...

  7. [bzoj1047][HAOI2007]理想的正方形_动态规划_单调队列

    理想的正方形 bzoj-1047 HAOI-2007 题目大意:有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 注释:$2\le a, ...

  8. BZOJ1047[HAOI2007]理想的正方形——二维ST表

    题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非 ...

  9. 【单调队列】bzoj1047 [HAOI2007]理想的正方形

    先把整个矩阵处理成b[n][m-K+1].c[n][m-K+1]大小的两个矩阵,分别存储每行每K个数中的最大.最小值,然后再通过b.c处理出d.e分别表示K*K大小的子矩阵中的最大.最小值即可.单调队 ...

随机推荐

  1. angular js自定义service的简单示例

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  2. TCP ------ TCP创建服务器中出现的套接字

    在服务器端,socket()返回的套接字用于监听(listen)和接受(accept)客户端的连接请求.这个套接字不能用于与客户端之间发送和接收数据. accept()接受一个客户端的连接请求,并返回 ...

  3. Install the Active Directory Administration Tools on Windows Server

    安装 Active Directory 管理工具 To manage your directory from an EC2 Windows instance, you need to install ...

  4. JS表单验证优化

    var validate = (function(){ var messages = { isEmail : '输入正确格式邮箱', isPhoneNum : '输入正确手机号' }; var val ...

  5. lesson 4 再谈继承多态,抽象类和接口

    再谈多态,抽象类和接口 上一次博客已经概念性的概述了继承多态,抽象类和接口,这次来具体的谈一谈他们之间的联系和需要注意的地方. 一.继承和多态:Inheritance (继承) & Polym ...

  6. Go 实现 soundex 算法

    [转]http://www.syyong.com/Go/Go-implements-the-soundex-algorithm.html SOUNDEX 返回由四个字符组成的代码 (SOUNDEX) ...

  7. [bzoj3524==bzoj2223][Poi2014]Couriers/[Coci 2009]PATULJCI——主席树+权值线段树

    题目大意 给定一个大小为n,每个数的大小均在[1,c]之间的数列,你需要回答m个询问,其中第i个询问形如\((l_i, r_i)\),你需要回答是否存在一个数使得它在区间\([l_i,r_i]\)中出 ...

  8. poj 2406 Power Strings(kmp循环节)

    题目链接:http://poj.org/problem?id=2406 题目大意:如果n%(n-next[n])==0,则存在重复连续子串,长度为n-next[n]. 例如:      a    b  ...

  9. 时间模块(time/date)

    在Python中,常用的表示方式的时间有:时间戳,字符串时间,元组时间(既年,月,日,时,分,秒,周几,一年中的第几天,时区)     time模块:   time.timezone: 获取当前标准时 ...

  10. DDD——让天下没有难调的程序

    https://www.linuxidc.com/Linux/2016-11/137343.htm DDD全称Data Display Debugger,当我第一次见到它时,它的界面着实让我吃了一惊, ...