DP/单调队列优化


  一眼看上去就是DP

  我想的naive的二维DP是酱紫滴:

    mx[i][j][k]表示以(i,j)为右下角的k*k的正方形区域内的最大值,mn[i][j][k]同理

    mx[i][j][k]=max(v[i][j],max(v[i-k+1][j-k+1],max(mx[i-1][j][k-1],mx[i][j-1][k-1]))),mn[i][j][k]同理

  这个DP是既爆空间又爆时间的……我把空间优化了一下:由于转移的时候只用到了i-1行的DP值,所以可以用滚动数组。

  但是时间上我优化不来了……

 //BZOJ 1047
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
using namespace std;
inline int getint(){
int v=,sign=; char ch=getchar();
while(ch<''||ch>''){ if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<=''){ v=v*+ch-''; ch=getchar();}
return v*sign;
}
const int N=,M=,INF=~0u>>;
typedef long long LL;
/******************tamplate*********************/
int a,b,n,ans=INF;
int mx[][N][M],mn[][N][M],v[N][N];
int main(){
#ifndef ONLINE_JUDGE
freopen("1047.in","r",stdin);
freopen("1047.out","w",stdout);
#endif
a=getint(); b=getint(); n=getint();
F(i,,a) F(j,,b) v[i][j]=getint();
F(i,,a){
int now=i&;
F(j,,b){
mx[now][j][]=mn[now][j][]=v[i][j];
F(k,,min(n,min(i,j))){
mx[now][j][k]=max(v[i][j],max(v[i-k+][j-k+],max(mx[now][j-][k-],mx[now^][j][k-])));
mn[now][j][k]=min(v[i][j],min(v[i-k+][j-k+],min(mn[now][j-][k-],mn[now^][j][k-])));
}
if (min(i,j)>=n) ans=min(ans,mx[now][j][n]-mn[now][j][n]);
}
}
printf("%d\n",ans);
return ;
}

(80分TLE)

  看了下题解:单调队列!

  豁然开朗,这不就是一个二维的滑动窗口吗?我个sb没想到啊……

  每行先做一遍单调队列优化DP,求出mx[i][j]表示以(i,j)为右端点的横着的n个格子的最大值(mn[i][j]同理)

  然后再对每列做一遍……(这时候每一格的值就代表了横着的n个格子的最优值)

  在对列进行DP的时候,为了节省(tou)空间(lan)我做完一列的DP就更新了一下答案……

P.S.感觉这个做法就是把一个二维的DP拆成(n+n)个一维DP分别搞……因为一维DP好搞、好优化= =所以总体上复杂度是降低了……(二维是n*n个状态,k的转移,一维是n个状态,转移可以优化到O(1),所以虽然一维DP要做2n遍,但总复杂度是$2×n^2$,更优)

 /**************************************************************
Problem: 1047
User: Tunix
Language: C++
Result: Accepted
Time:1980 ms
Memory:13240 kb
****************************************************************/ //BZOJ 1047
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
using namespace std;
inline int getint(){
int v=,sign=; char ch=getchar();
while(ch<''||ch>''){ if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<=''){ v=v*+ch-''; ch=getchar();}
return v*sign;
}
const int N=,M=,INF=~0u>>;
typedef long long LL;
/******************tamplate*********************/
int a,b,n,ans=INF;
int mx[N][N],mn[N][N],Q[N],t1[N],t2[N],v[N][N];
void get_row(){
int l=,r=-;
F(i,,a){
l=,r=-;
F(j,,b){
while(l<=r && v[i][Q[r]]<=v[i][j])r--;
Q[++r]=j;
while(l<=r && j-Q[l]>=n) l++;
if (j>=n) mx[i][j]=v[i][Q[l]];
}
l=,r=-;
F(j,,b){
while(l<=r && v[i][Q[r]]>=v[i][j])r--;
Q[++r]=j;
while(l<=r && j-Q[l]>=n) l++;
if (j>=n) mn[i][j]=v[i][Q[l]];
}
}
}
void get_line(){
int l,r;
F(j,n,b){
l=,r=-;
F(i,,a){
while(l<=r && mx[Q[r]][j]<=mx[i][j]) r--;
Q[++r]=i;
while(l<=r && i-Q[l]>=n) l++;
if (i>=n) t1[i]=mx[Q[l]][j];
}
l=,r=-;
F(i,,a){
while(l<=r && mn[Q[r]][j]>=mn[i][j]) r--;
Q[++r]=i;
while(l<=r && i-Q[l]>=n) l++;
if (i>=n) t2[i]=mn[Q[l]][j];
}
F(i,n,a) ans=min(ans,t1[i]-t2[i]);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1047.in","r",stdin);
freopen("1047.out","w",stdout);
#endif
a=getint(); b=getint(); n=getint();
F(i,,a) F(j,,b) v[i][j]=getint();
get_row();
get_line();
printf("%d\n",ans);
return ;
}

(正解)

【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] 理想的正方形 【单调队列】

    题目链接:BZOJ - 1047 题目分析 使用单调队列在 O(n^2) 的时间内求出每个 n * n 正方形的最大值,最小值.然后就可以直接统计答案了. 横向有 a 个单调队列(代码中是 Q[1] ...

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

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

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

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

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

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

  7. [bzoj 1047][HAOI2007]理想正方形(单调队列)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1047 分析: 第一感觉二维线段树当然没问题但是挺慢的. 注意到要求的正方形形中的最大最小边长是 ...

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

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

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更 ...

  10. 【单调队列】bzoj 1407 [HAOI2007]理想的正方形

    [题意] 给定一个n*m的矩阵,求所有大小为k*k的正方形中(最大值-最小值)的最小值 [思路] 先横着算出每一行的长度为k的窗口内的最大值,变成一个n*(m-k+1)的矩阵mx 再竖着算出每一列的长 ...

随机推荐

  1. 返回json格式时间,解析时间

    传入:Json格式的时间 JS如下: yyyy-M(MM)-d(dd) H(HH):m(mm):s(ss) function timeStamp2String(time) { var data=tim ...

  2. 【Winform】DataTable绑定到ComboBox

    我们从数据库中查询出来的数据存放在Datatable中 1.DataTable绑定到ComboBox上 cmbRole.DataSource = datatable; cmbRole.DisplayM ...

  3. Spark基础排序+二次排序(java+scala)

    1.基础排序算法 sc.textFile()).reduceByKey(_+_,).map(pair=>(pair._2,pair._1)).sortByKey(false).map(pair= ...

  4. linux BASH shell设置字体与背景颜色

    linux BASH shell下设置字体及背景颜色的方法. BASH shell下设置字体及背景颜色  echo -e "\e[31mtest\e[41m"  \e[30m 将字 ...

  5. python 解析XML python模块xml.dom解析xml实例代码

    分享下python中使用模块xml.dom解析xml文件的实例代码,学习下python解析xml文件的方法. 原文转自:http://www.jbxue.com/article/16587.html ...

  6. MySQL: InnoDB 还是 MyISAM?

    MyISAM存储引擎 MyISAM是 默认存储引擎.它基于更老的ISAM代码,但有很多有用的扩展.MyISAM存储引擎的一些特征:·      所有数据值先存储低字节.这使得数据机和操作系统分离.二进 ...

  7. 关于编程语言(转/收藏)-原文作者:韩天峰(Rango)

    原文在这里:http://rango.swoole.com/archives/405 容易让人记住的文章,要么引起共鸣,要么催人奋进.一句话,你已走过,而我也在路上. 最近群里很多朋友询问我是如何学习 ...

  8. 基于socket的客户端和服务端聊天机器人

    服务端代码如下: using System;using System.Net;using System.Net.Sockets;using System.Text;using System.Threa ...

  9. [原创] PostgreSQL Plus Advanced Server在Windows中配置双机热备流复制

    一.系统环境 操作系统:Windows Server 2003/2008 两个节点分别为master与slave. 主节点master:172.27.19.28 备机点slave:172.27.19. ...

  10. 掌握这两个技术点,你可以玩转AppCan前端开发

    “AppCan的前端开发其实非常简单,只要掌握两方面的技术即可.一方面是会使用栅格布局完成UI的界面排版,另外一方面就是使用AppCan MVVM模型来完成整个页面构造和用户操作逻辑.” 在2016A ...