bzoj 1047

横着用单调队列求最值,再竖着做单调队列即可

 1 #include<bits/stdc++.h>
 2 #define inc(i,l,r) for(int i=l;i<=r;i++)
 3 #define dec(i,l,r) for(int i=l;i>=r;i--)
 4 #define link(x) for(edge *j=h[x];j;j=j->next)
 5 #define mem(a) memset(a,0,sizeof(a))
 6 #define inf 1e9
 7 #define ll long long
 8 #define succ(x) (1<<x)
 9 #define NM 1000+5
10 using namespace std;
11 int read(){
12     int x=0,f=1;char ch=getchar();
13     while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
14     while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
15     return x*f;
16 }
17 int n,m,p,a[NM][NM],b[NM][NM],c[NM][NM],qt,qh,q[NM],_q[NM],_qh,_qt,s;
18 int main(){
19 //    freopen("data.in","r",stdin);
20     n=read();m=read();p=read();
21     inc(i,1,n)
22     inc(j,1,m)a[i][j]=read();
23     inc(i,1,n){
24         qh=1;qt=0;mem(q);
25         inc(j,1,p){
26             while(qh<=qt&&a[i][q[qt]]<=a[i][j])qt--;
27             q[++qt]=j;
28         }
29         b[i][p]=a[i][q[qh]];
30         inc(j,p+1,m){
31             while(qh<=qt&&q[qh]<j-p+1)qh++;
32             while(qh<=qt&&a[i][q[qt]]<=a[i][j])qt--;
33             q[++qt]=j;
34             b[i][j]=a[i][q[qh]];
35         }
36         qh=1;qt=0;mem(q);
37         inc(j,1,p){
38             while(qh<=qt&&a[i][q[qt]]>=a[i][j])qt--;
39             q[++qt]=j;
40         }
41         c[i][p]=a[i][q[qh]];
42         inc(j,p+1,m){
43             while(qh<=qt&&q[qh]<j-p+1)qh++;
44             while(qh<=qt&&a[i][q[qt]]>=a[i][j])qt--;
45             q[++qt]=j;
46             c[i][j]=a[i][q[qh]];
47         }
48     }
49 /*    inc(j,1,m)printf("%d ",b[i][j]);printf("\n");}
50     inc(i,1,n){
51     inc(j,1,m)printf("%d ",c[i][j]);printf("\n");}*/
52     s=inf;
53     inc(j,p,m){
54         _qh=qh=1;_qt=qt=0;mem(q);mem(_q);
55         inc(i,1,p){
56             while(qh<=qt&&b[q[qt]][j]<=b[i][j])qt--;
57             q[++qt]=i;
58             while(_qh<=_qt&&c[_q[_qt]][j]>=c[i][j])_qt--;
59             _q[++_qt]=i;
60         }
61         s=min(s,b[q[qh]][j]-c[_q[_qh]][j]);
62 //        printf("%d ",s);
63         inc(i,p+1,n){
64             while(qh<=qt&&q[qh]<i-p+1)qh++;
65             while(qh<=qt&&b[q[qt]][j]<=b[i][j])qt--;
66             q[++qt]=i;
67             while(_qh<=_qt&&_q[_qh]<i-p+1)_qh++;
68             while(_qh<=_qt&&c[_q[_qt]][j]>=c[i][j])_qt--;
69             _q[++_qt]=i;s=min(s,b[q[qh]][j]-c[_q[_qh]][j]);
70 //            printf("%d ",b[q[qh]][j]-c[_q[_qh]][j]);
71         }
72 //        printf("\n");
73     }
74     printf("%d\n",s);
75     return 0;
76 }

时间: 2024-10-14 11:00:15

bzoj 1047的相关文章

BZOJ 1047 [HAOI2007]理想的正方形

[看了题解才会做 这是一个典型的二维滑动窗口问题~ 二维滑动窗口问题的处理方法可以类比一维滑动窗口的处理方法 首先将矩阵分解成B个列,对这B个列分别用单调队列维护一个长度为N的一维滑动窗口.记录colmax[i][j]为第j列第i行的元素(即第j个列的第i个元素)到第j列第i-N+1的元素(即第j个列的第i-N+1个元素)的最大值.这个用单调队列随便维护一下就好啦~ 然后将矩阵分解成A个行,对这A个行再分别用单调队列维护一个长度为N的一维滑动窗口.记录rowmax[i][j]为colmax[i]

[BZOJ]1047 理想的正方形(HAOI2007)

真·水题.小C本来是不想贴出来的,但是有一股来自东方的神秘力量催促小C发出来. Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔. Output 仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值. Sample Input 5

【BZOJ 1047】 [HAOI2007]理想的正方形

1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1685  Solved: 891 [Submit][Status] Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔.

[BZOJ 1047][HAOI 2007]理想的正方形(二维滑动窗口+单调队列)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1047 思路:裸的二维上的滑动窗口问题,可以借鉴一维滑动窗口的思路.首先预处理出每一列j的.以第i行元素为结尾.长度为n的区间的最大值maxv[i][j].最小值minv[i][j],然后再搞每一行,求出以每一行i结尾.行标上长度为n的区间.以第j列结尾.列标上长度为n的区间得到的二维区间最大值与最小值之差,遍历每一行得到这个差的最小值即为答案. #include <iostrea

bzoj 1047 单调队列

做4次单调队列优化DP. 1 /************************************************************** 2 Problem: 1047 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:2088 ms 7 Memory:16756 kb 8 ****************************************************************/ 9 10

BZOJ 1047 HAOI2007 理想的正方形 单调队列

题目大意:给定一个a*b的矩阵,求一个n*n的子矩阵,使矩阵中的最大值与最小值之差最小 对于每行维护一个单调递减的队列.再弄一个竖着的队列.维护n个格子之内的最大值就可以 两遍统计出最大值和最小值 然后得到ans就可以 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 1010 using namespace std; struct abcd

BZOJ 1047 理想的正方形

       看到这到题,第一反应当然是暴搜一遍,但是数据较大,暴搜铁定过不了,自然想到进行优化,优化的方案很多,每个人的思路可能不同,在这里我的思路仅供参考.         我的想法是用单调队列.单调栈,当然简单的单调队列.单调栈只适用于一行数据,对于这道题要进行一定的组合和变换.根据题目的介绍,可以大致总结出以下信息:第一,矩阵由b组长度为a的数列组成:第二,求的范围是m*m.因而,我们可以先取第一行进行考虑,简单的理解为依次输入每一个数据,输入一个求取一下后m个数据中的最大值,并将之记录

BZOJ 1047 理想的正方形(单调队列)

刚开始用二维RMQ直接给超内存了... 用单调队列可以做到O(n^2)的复杂度.具体是先把每行用单调队列处理一下.再把处理后的用列单调队列处理下. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # in

BZOJ 1047 HAOI 2007 理想的正方形 单调队列

题目大意:给出一个矩阵,求出一个k*k的子矩阵,使得这个矩阵中最大值和最小值的差最小,输出这个差值. 思路:利用单调队列维护每一行的数字,求出一个数字前面k个数字中的最大值和最小值,然后在列上暴力求出真个矩阵的最大值和最小值,总时间复杂度O(M*M+M*M*K). CODE: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algor