bzoj1047 单调队列

来源:互联网 发布:nc.windows.app.23787 编辑:程序博客网 时间:2024/06/14 00:58

Description

  有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值
的差最小。

Input

  第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每
行相邻两数之间用一空格分隔。
100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000
Output

  仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。

Sample Input

5 4 2

1 2 5 6

0 17 16 0

16 17 2 1

2 10 2 1

1 2 2 2
Sample Output

1
还在为学不会单调队列而苦恼么?
还在看一篇又一篇写的很诡异的博客么?
我们已经为你准备了一大堆习题来教你单调队列,我们保证你绝对做到吐
单调队列单调队列顾名思义队列里面的元素是有单调性的要么递增要么递减
我们考虑,一个靠后的点虽然可能在数值上不占优势但是它可以更新的更远,但是如果他在数值上也占优势的话那么前面的点不就很没用了么,那么就让他们全部出队。当队列滑动的过程中要把不合题意的点出队。这就是单调队列优化dp
那么这个题也就比较明确了。
那么此题其实是一个非常裸的二维单调队列。
用max【i】【j】表示以(i,j)为右下角的最大值
那么我们先求出每一行的情况然后求出前i行的情况

#include<cstdio>#include<cstring>#include<utility>#include<algorithm>#include<iostream>#include<queue>#include<stack>#include<cmath>#include<cstdlib>#include<ctime>using namespace std;inline int read(){    char ch='*';    int f=1;    while(!isdigit(ch=getchar())) if(ch=='-') f=-1;    int num=ch-'0';    while(isdigit(ch=getchar())) num=num*10+ch-'0';    return num*f;}const int N=1005;int mp[N][N],h[N],t[N],Q[N],q[N][N];int mx[N][N],mn[N][N];int s,e,a,b,n;void getmax(){    for(register int i=1;i<=b;++i)        h[i]=1,t[i]=0;    for(register int i=1;i<=a;++i){        for(register int j=1;j<=b;++j)        {            while(h[j]<=t[j]&&i-q[j][h[j]]>=n) ++h[j];            while(h[j]<=t[j]&&mp[q[j][t[j]]][j]<=mp[i][j]) --t[j];            q[j][++t[j]]=i;        }        e=0,s=1;        for(register int j=1;j<=b;j++){            while(s<=e&&j-Q[s]>=n) ++s;            while(s<=e&&mp[q[Q[e]][h[Q[e]]]][Q[e]]<=mp[q[j][h[j]]][j]) e--;            Q[++e]=j;            mx[i][j]=mp[q[Q[s]][h[Q[s]]]][Q[s]];        }    }    return ;}void getmin(){    for(register int i=1;i<=b;++i)        h[i]=1,t[i]=0;    for(register int i=1;i<=a;++i){        for(register int j=1;j<=b;++j)        {            while(h[j]<=t[j]&&i-q[j][h[j]]>=n) ++h[j];            while(h[j]<=t[j]&&mp[q[j][t[j]]][j]>=mp[i][j]) --t[j];            q[j][++t[j]]=i;        }        e=0,s=1;        for(register int j=1;j<=b;j++){            while(s<=e&&j-Q[s]>=n) ++s;            while(s<=e&&mp[q[Q[e]][h[Q[e]]]][Q[e]]>=mp[q[j][h[j]]][j]) e--;            Q[++e]=j;            mn[i][j]=mp[q[Q[s]][h[Q[s]]]][Q[s]];        }    }    return ;}int main(){    a=read();b=read();n=read();    for(register int i=1;i<=a;i++)        for(register int j=1;j<=b;j++)            mp[i][j]=read();    getmax();    getmin();    int ans=0x7fffffff;    for(int i=n;i<=a;i++)        for(register int j=n;j<=b;j++)            ans=min(ans,mx[i][j]-mn[i][j]);    printf("%d\n",ans);    return 0;}
阅读全文
0 0
原创粉丝点击