[BZOJ 1047]理想的正方形

Link:

BZOJ 1047 传送门

Solution:

(1)先横向用单调队列求出每个数左边$n$个数中的最值

(2)再纵向利用横向的结果用单调队列进行相同的操作

通过以上操作将$a*b$的矩阵转化为了$(a-n+1)*(b-n+1)$的矩阵

相当于每个正方形被缩成了一个点,而每个点的最值就代表着原正方形中的最值

 

Tip:

1、又被$1<<27$坑了……以后还是都设为$1<<30$吧

2、将二维转化为两个一维的合并的思想很劲啊,和二维数据结构的处理方式很类似啊

 

Code:

#include <bits/stdc++.h>

using namespace std;
const int MAXN=1005;//res的初始值一定要设大,如果上限为1e9则要设为(1<<30) 
int q1[MAXN],q2[MAXN],l1,l2,r1,r2,res=1<<30;
int n,m,k,dat[MAXN][MAXN],mx[MAXN][MAXN],mn[MAXN][MAXN];

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&dat[i][j]),mx[i][j]=mn[i][j]=dat[i][j];
    
    for(int i=1;i<=n;i++)
    {
        l1=l2=1;r1=r2=0;
        for(int j=1;j<=m;j++)
        {
            while(l1<=r1&&j-q1[l1]>=k) l1++;
            while(l2<=r2&&j-q2[l2]>=k) l2++;
            
            while(l1<=r1&&dat[i][j]>dat[i][q1[r1]]) r1--;
            while(l2<=r2&&dat[i][j]<dat[i][q2[r2]]) r2--;
            q1[++r1]=j;mx[i][j]=max(mx[i][j],dat[i][q1[l1]]);
            q2[++r2]=j;mn[i][j]=min(mn[i][j],dat[i][q2[l2]]);
        }
    }
    
    for(int i=k;i<=m;i++)
    {
        l1=l2=1;r1=r2=0;
        for(int j=1;j<=n;j++)
        {
            while(l1<=r1&&j-q1[l1]>=k) l1++;
            while(l2<=r2&&j-q2[l2]>=k) l2++;
            
            while(l1<=r1&&mx[j][i]>mx[q1[r1]][i]) r1--;
            while(l2<=r2&&mn[j][i]<mn[q2[r2]][i]) r2--;
            q1[++r1]=j;q2[++r2]=j;
            //要保证j>=k 
            if(j>=k) res=min(res,mx[q1[l1]][i]-mn[q2[l2]][i]);
        }
    }
    printf("%d",res);
    return 0;
}

 

posted @ 2018-07-08 21:37  NewErA  阅读(444)  评论(0编辑  收藏  举报