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 #include <cstdio>
11 #define N 1010
12
13 struct Pair {
14     int i, j, v;
15     Pair(){}
16     Pair( int i, int j, int v ):i(i),j(j),v(v){}
17 };
18
19 int n, m, r, ans;
20 int v[N][N], dp[N][N], dmin[N][N], dmax[N][N];
21 Pair qu[N]; int bg, ed;
22
23 int dodp() {
24     //  min
25     for( int i=1; i<=n; i++ ) {
26         bg=1, ed=0;
27         for( int j=1; j<=m; j++ ) {
28             while( bg<=ed && qu[bg].j<j-r+1 ) bg++;
29             while( bg<=ed && qu[ed].v>v[i][j] ) ed--;
30             qu[++ed] = Pair(i,j,v[i][j]);
31             dp[i][j] = qu[bg].v;
32         }
33     }
34     for( int j=1; j<=m; j++ ) {
35         bg=1, ed=0;
36         for( int i=1; i<=n; i++ ) {
37             while( bg<=ed && qu[bg].i<i-r+1 ) bg++;
38             while( bg<=ed && qu[ed].v>dp[i][j] ) ed--;
39             qu[++ed] = Pair(i,j,dp[i][j]);
40             dmin[i][j] = qu[bg].v;
41         }
42     }
43     //  max
44     for( int i=1; i<=n; i++ ) {
45         bg=1, ed=0;
46         for( int j=1; j<=m; j++ ) {
47             while( bg<=ed && qu[bg].j<j-r+1 ) bg++;
48             while( bg<=ed && qu[ed].v<v[i][j] ) ed--;
49             qu[++ed] = Pair(i,j,v[i][j]);
50             dp[i][j] = qu[bg].v;
51         }
52     }
53     for( int j=1; j<=m; j++ ) {
54         bg=1, ed=0;
55         for( int i=1; i<=n; i++ ) {
56             while( bg<=ed && qu[bg].i<i-r+1 ) bg++;
57             while( bg<=ed && qu[ed].v<dp[i][j] ) ed--;
58             qu[++ed] = Pair(i,j,dp[i][j]);
59             dmax[i][j] = qu[bg].v;
60         }
61     }
62     int ans = 2000000001;
63     for( int i=r; i<=n; i++ )
64         for( int j=r; j<=m; j++ ) {
65             int tans = dmax[i][j]-dmin[i][j];
66             if( ans>tans ) ans=tans;
67         }
68     /*  debug
69     fprintf( stderr, "n=%d m=%d r=%d\n", n, m, r );
70     fprintf( stderr, "v:\n" );
71     for( int i=1; i<=n; i++ ) {
72         for( int j=1; j<=m; j++ )
73             fprintf( stderr, "%2d ", v[i][j] );
74         fprintf( stderr, "\n" );
75     }
76     fprintf( stderr, "dmin:\n" );
77     for( int i=1; i<=n; i++ ) {
78         for( int j=1; j<=m; j++ )
79             fprintf( stderr, "%2d ", dmin[i][j] );
80         fprintf( stderr, "\n" );
81     }
82     fprintf( stderr, "dmax:\n" );
83     for( int i=1; i<=n; i++ ) {
84         for( int j=1; j<=m; j++ )
85             fprintf( stderr, "%2d ", dmax[i][j] );
86         fprintf( stderr, "\n" );
87     }
88     */
89     return ans;
90 }
91 int main() {
92     scanf( "%d%d%d", &n, &m, &r );
93     for( int i=1; i<=n; i++ )
94         for( int j=1; j<=m; j++ )
95             scanf( "%d", &v[i][j] );
96     printf( "%d\n", dodp() );
97 }

时间: 2024-08-29 06:35:42

bzoj 1047 单调队列的相关文章

【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更快,只有O(n^2).而这货是n^2log^2n的建树...虽然查询是log^2n...但是建树那里就tle了.. 那么说题解... 先orz下,好神.. 我怎么没想到单调队列orz 首先我们维护 行 的单调队列,更新每个点在 列 距离内的最小and最大的值 然后我们维护 列 的单调队列,更新每个点

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

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

没有复杂结构甚至不长但是写起来就很想死的代码类型 原理非常简单,就是用先用单调队列处理出mn1[i][j]表示i行的j到j+k-1列的最小值,mx1[i][j]表示i行的j到j+k-1列的最大值 然后就变成求单列最大最小值,用上面同样的方法处理出对于列的mn2mx2即可 #include<iostream> #include<cstdio> using namespace std; const int N=1005; int n,m,k,a[N][N],mn1[N][N],mx1[

BZOJ 1855 股票交易(单调队列优化DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1855 题意:最近lxhgww又迷上了投资股票, 通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每 个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BS

1047: [HAOI2007]理想的正方形——二维单调队列

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 对每一行维护一个单调队列,保存在lmin[][],lmax[][] 然后对每一列维护一个单调队列,最后n*n枚举 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #define clr(a,b) memset(a,b,sizeof(a)) cons

【bzoj 1414】对称的正方形 单调队列+manacher

Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一个奇特的数,就是矩阵中上下对称且左右对称的正方形子矩阵的个数. Orez自然很想知道这个数是多少,可是矩阵太大,无法去数.只能请你编个程序来计算出这个数. Input 文件的第一行为两个整数n和m.接下来n行每行包含m个正整数,表示Orez得到的矩阵. Output 文件中仅包含一个整数answer

单调队列 BZOJ 2096 [Poi2010]Pilots

2096: [Poi2010]Pilots Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 819  Solved: 418[Submit][Status][Discuss] Description Tz又耍畸形了!!他要当飞行员,他拿到了一个飞行员测试难度序列,他设定了一个难度差的最大值,在序列中他想找到一个最长的子串,任意两个难度差不会超过他设定的最大值.耍畸形一个人是不行的,于是他找到了你. Input 输入:第一行两个有空格隔开的整数k(0

BZOJ 1342 Baltic2007 Sound静音问题 单调队列

题目大意:给定一个长度为n的序列,求哪些长度为m的区间满足区间内最大值与最小值之差小于等于c 利用单调队列维护区间内的最大值和最小值- - 硬搞就可以了- - 刷刷水题真爽- - #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 1001001 using namespace std; int n,m,c,a[M]; int q_ma