题目链接:BZOJ - 1047

题目分析

使用单调队列在 O(n^2) 的时间内求出每个 n * n 正方形的最大值,最小值。然后就可以直接统计答案了。

横向有 a 个单调队列(代码中是 Q[1] 到 Q[a] ),维护每行当前枚举区间的单调队列。

纵向一个单调队列(代码中是 Q[0] ),求出当前枚举区间的每行的单调队列后,就得到了每行的这个区间的最小值(最大值),就相当于一个长度为行数的数组,然后纵向做单调队列,求出的就是正方形的最值了。

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> using namespace std; const int MaxN = 1000 + 5, INF = 999999999; int a, b, n, Ans;
int Map[MaxN][MaxN], Q[MaxN][MaxN], F[MaxN], Head[MaxN], Tail[MaxN], Min[MaxN][MaxN], Max[MaxN][MaxN];
//Q[0]是纵向的单调队列 inline int gmin(int a, int b) {return a < b ? a : b;}
inline int gmax(int a, int b) {return a > b ? a : b;} void Get_Min()
{
for (int i = 1; i <= a; ++i)
{
Head[i] = 1;
Tail[i] = 0;
}
for (int i = 1; i <= b; ++i)
{
for (int j = 1; j <= a; ++j)
{
if (i > n && Head[j] <= Tail[j] && Q[j][Head[j]] == i - n) ++Head[j];
while (Head[j] <= Tail[j] && Map[j][i] < Map[j][Q[j][Tail[j]]]) --Tail[j];
Q[j][++Tail[j]] = i;
}
if (i >= n)
{
Head[0] = 1; Tail[0] = 0;
for (int j = 1; j <= a; ++j)
{
F[j] = Map[j][Q[j][Head[j]]];
if (j > n && Head[0] <= Tail[0] && Q[0][Head[0]] == j - n) ++Head[0];
while (Head[0] <= Tail[0] && F[j] < F[Q[0][Tail[0]]]) --Tail[0];
Q[0][++Tail[0]] = j;
if (j >= n) Min[j][i] = F[Q[0][Head[0]]];
}
}
}
} void Get_Max()
{
for (int i = 1; i <= a; ++i)
{
Head[i] = 1;
Tail[i] = 0;
}
for (int i = 1; i <= b; ++i)
{
for (int j = 1; j <= a; ++j)
{
if (i > n && Head[j] <= Tail[j] && Q[j][Head[j]] == i - n) ++Head[j];
while (Head[j] <= Tail[j] && Map[j][i] > Map[j][Q[j][Tail[j]]]) --Tail[j];
Q[j][++Tail[j]] = i;
}
if (i >= n)
{
Head[0] = 1; Tail[0] = 0;
for (int j = 1; j <= a; ++j)
{
F[j] = Map[j][Q[j][Head[j]]];
if (j > n && Head[0] <= Tail[0] && Q[0][Head[0]] == j - n) ++Head[0];
while (Head[0] <= Tail[0] && F[j] > F[Q[0][Tail[0]]]) --Tail[0];
Q[0][++Tail[0]] = j;
if (j >= n) Max[j][i] = F[Q[0][Head[0]]];
}
}
}
} int main()
{
scanf("%d%d%d", &a, &b, &n);
for (int i = 1; i <= a; ++i)
for (int j = 1; j <= b; ++j)
scanf("%d", &Map[i][j]);
Get_Min();
Get_Max();
Ans = INF;
for (int i = n; i <= a; ++i)
for (int j = n; j <= b; ++j)
Ans = gmin(Ans, Max[i][j] - Min[i][j]);
printf("%d\n", Ans);
return 0;
}

  

[BZOJ 1047] [HAOI2007] 理想的正方形 【单调队列】的更多相关文章

  1. bzoj 1047 : [HAOI2007]理想的正方形 单调队列dp

    题目链接 1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2369  Solved: 1266[Submi ...

  2. BZOJ 1047: [HAOI2007]理想的正方形( 单调队列 )

    单调队列..先对每一行扫一次维护以每个点(x, y)为结尾的长度为n的最大最小值.然后再对每一列扫一次, 在之前的基础上维护(x, y)为结尾的长度为n的最大最小值. 时间复杂度O(ab) (话说还是 ...

  3. BZOJ 1047: [HAOI2007]理想的正方形 单调队列瞎搞

    题意很简明吧? 枚举的矩形下边界和右端点即右下角,来确定矩形位置: 每一个纵列开一个单调队列,记录从 i-n+1 行到 i 行每列的最大值和最小值,矩形下边界向下推移的时候维护一下: 然后在记录的每一 ...

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

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

  5. P2216 [HAOI2007]理想的正方形 (单调队列)

    题目链接:P2216 [HAOI2007]理想的正方形 题目描述 有一个 \(a\times b\)的整数组成的矩阵,现请你从中找出一个 \(n\times n\)的正方形区域,使得该区域所有数中的最 ...

  6. bzoj 1047: [HAOI2007]理想的正方形【单调队列】

    没有复杂结构甚至不长但是写起来就很想死的代码类型 原理非常简单,就是用先用单调队列处理出mn1[i][j]表示i行的j到j+k-1列的最小值,mx1[i][j]表示i行的j到j+k-1列的最大值 然后 ...

  7. BZOJ 1047: [HAOI2007]理想的正方形

    题目 单调队列是个很神奇的东西,我以前在博客写过(吧) 我很佩服rank里那些排前几的大神,700ms做了时限10s的题,简直不能忍.(但是我还是不会写 我大概一年半没写单调队列,也有可能根本没有写过 ...

  8. Luogu 2216[HAOI2007]理想的正方形 - 单调队列

    Solution 二维单调队列, 这个数组套起来看得我眼瞎... Code #include<cstdio> #include<algorithm> #include<c ...

  9. [HAOI2007] 理想的正方形 (单调队列)

    题目链接 Solution MD,经过这道题,算是掌握单调队列了... 可以先预处理出点 \((i,j)\) 往上 \(n\) 的最大值和最小值. 然后再横着做一遍单调队列即可. Code #incl ...

随机推荐

  1. [AngularJS] Extract predicate methods into filters for ng-if and ng-show

    Leaking logic in controllers is not an option, filters are a way to refactor your code and are compa ...

  2. 一行代码解决Android M新的运行时权限问题

    Android M运行时权限是个啥东西 啥是运行时权限呢?Android M对权限管理系统进行了改版,之前我们的App需要权限,只需在manifest中申明即可,用户安装后,一切申明的权限都可来去自如 ...

  3. android 72 确定取消对话框,单选对话框,多选对话框

    package com.itheima.dialog; import android.os.Bundle; import android.app.Activity; import android.ap ...

  4. c语言中的 %u 什么意思啊?

    %d 有符号10进制整数 %i 有符号10进制整数 %o 无符号8进制整数 %u 无符号10进制整数 %x 无符号的16进制数字,并以小写abcdef表示%X 无符号的16进制数字,并以大写ABCDE ...

  5. linux bash下 快捷键

    c + a # 光标跳转到最左 c + e # 光标跳转到最后 c + w # 删除最后输入的单词 c + u # 删除整行 c + k # 删除光标到末尾 c + l # 清屏 c + z # 挂起 ...

  6. JS 自定义回调函数callback

    1 应用场景:js的异步加载,在get,post,ajax异步加载的时候,可能对应的请求没有完成,这时需要使用请求回来的数据作为参数调用其他函数,这时就需要使用回调函数. 2 回调函数作用:等待函数调 ...

  7. python基础知识五

    数据结构基本上就是---它们可以处理一些数据的结构.或者说,它们是用来存储一组相关数据的. python中有三种内建的数据结构---列表.元祖和字典. 我们将会学习如何使用它们,以及它们如何使编程变得 ...

  8. NPOI的使用

    简介:NPOI是POI(APATCH的一个开源项目)项目的.NET版本,最初的POI只用于JAVA来操作EXCEL or WORD等微软OLE2组件项目.使用NPOI可以完成在你没有安装Office或 ...

  9. iOS开发内购图文教程

    2015年最全的内购图文教程,首先是填各种资料,最后是代码,废话不多说,直接上图 ======================第一部分协议=============== 第一步.png 第二步.jpg ...

  10. Spring Security Encryption三种加密方式

    Encryption One-way encryption       单项加密,客户端将要传递的值先加密(使用特定的加密方法),将原值和加密好的值传递过去,服务器端将原始数据也进行一次加密(两者加密 ...