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. FileSystemWatcher用法详解

    FileSystemWatcher控件主要功能: 监控指定文件或目录的文件的创建.删除.改动.重命名等活动.可以动态地定义需要监控的文件类型及文件属性改动的类型. 1.常用的几个基本属性: (1) P ...

  2. asp.net mvc JQGrid

    http://mikedormitorio.azurewebsites.net/BlogPost/jqgrid-series-part-1-loading-data-to-a-jqgrid-on-an ...

  3. [原]Django调试工具--django-debug-toolbar

    请摒弃简单粗暴的print --马云 我比较习惯在windows中安装pycharm开发,项目部署在虚拟机中,在本地浏览器中查看效果,这种方式在调试上会有点麻烦,django-debug-toolba ...

  4. 怎样用foreach去修改数组之中的数据

    $table_exchange=array(1,2,3,4,5,6,7,8); foreach ($table_exchange as $b=>$c){ $table_exchange[$b]= ...

  5. WordPress 非插件实现拦截无中文留言

    Some Chinese Please 插件可以拦截不带中文字的留言,之前本博客一直在用效果不错,不写入数据库,可有效地减少 spam 对服务器的无谓使用,其实可以将插件简化一下,直接用代码实现.将下 ...

  6. MySQL: ON DUPLICATE KEY UPDATE 用法 避免重复插入数据

    INSERT INTO osc_visit_stats(stat_date,type,id,view_count) VALUES (?,?,?,?) ON DUPLICATEKEY UPDATE vi ...

  7. SLF4J日志门面

    SLF4J官网:http://www.slf4j.org/ SLF4J的作用通俗点讲,就是可以让我们的项目以最小的代价更换不同的日志系统.无需修改代码,只需要添加.删除相应的jar包和配置文件. 1. ...

  8. 倒水问题 (codevs 1226) 题解

    [问题描述] 有两个无刻度标志的水壶,分别可装x升和y升 ( x,y 为整数且均不大于100)的水.设另有一水缸,可用来向水壶灌水或接从水壶中倒出的水, 两水壶间,水也可以相互倾倒.已知x升壶为空壶, ...

  9. R语言的日期运算

    写hive SQL查询, 需要从导入的参数, 自动累加日期. 从而实现一个自动的,多个日期的统计过程 R语言的日期运算超级简单. > test<-Sys.Date() > test ...

  10. STM32F0xx_EXIT中断配置详细过程

    Ⅰ.概述 EXIT外部中断在使用到按键或者开关控制等应用中比较常见,低功耗中断唤醒也是很常见的一种.因此,EXIT在实际项目开发中也是比较常见的一种. STM32F0中外部中断EXIT属于中断和事件的 ...