bzoj1047: [HAOI2007]理想的正方形(單調佇列)

Hanks_o發表於2018-02-01

題目傳送門
水一發。

解法:
分最大值和最小值咯。
然後hang[i][j]表示第i行以j結尾往前數n個的最大值或最小值。
做完行之後做列。
lie[i][j]表示以(i,j)為右下角的n*n的矩陣的最大值或最小值。
跑兩次單調佇列就行了呀。。

程式碼實現:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int head,tail,list[1100];
int map[1100][1100],hang_mx[1100][1100],lie_mx[1100][1100],hang_mn[1100][1100],lie_mn[1100][1100];
int main() {
    int a,b,n;scanf("%d%d%d",&a,&b,&n);
    for(int i=1;i<=a;i++)for(int j=1;j<=b;j++)scanf("%d",&map[i][j]); 
    for(int i=1;i<=a;i++) {
        head=1;tail=1;list[1]=1;
        for(int j=2;j<n;j++) {
            while(head<=tail&&map[i][j]>=map[i][list[tail]])tail--;
            list[++tail]=j;
        }
        for(int j=n;j<=b;j++) {
            while(head<=tail&&map[i][j]>=map[i][list[tail]])tail--;
            list[++tail]=j;
            while(head<tail&&list[head]<j-n+1)head++;
            hang_mx[i][j]=map[i][list[head]];
        }
        head=1;tail=1;list[1]=1;
        for(int j=2;j<n;j++) {
            while(head<=tail&&map[i][j]<=map[i][list[tail]])tail--;
            list[++tail]=j;
        }
        for(int j=n;j<=b;j++) {
            while(head<=tail&&map[i][j]<=map[i][list[tail]])tail--;
            list[++tail]=j;
            while(head<tail&&list[head]<j-n+1)head++;
            hang_mn[i][j]=map[i][list[head]];
        }
    }
    for(int j=n;j<=b;j++) {
        head=1;tail=1;list[1]=1;
        for(int i=2;i<n;i++) {
            while(head<=tail&&hang_mx[i][j]>=hang_mx[list[tail]][j])tail--;
            list[++tail]=i;
        }
        for(int i=n;i<=a;i++) {
            while(head<=tail&&hang_mx[i][j]>=hang_mx[list[tail]][j])tail--;
            list[++tail]=i;
            while(head<tail&&list[head]<i-n+1)head++;
            lie_mx[i][j]=hang_mx[list[head]][j];
        }
        head=1;tail=1;list[1]=1;
        for(int i=2;i<n;i++) {
            while(head<=tail&&hang_mn[i][j]<=hang_mn[list[tail]][j])tail--;
            list[++tail]=i;
        }
        for(int i=n;i<=a;i++) {
            while(head<=tail&&hang_mn[i][j]<=hang_mn[list[tail]][j])tail--;
            list[++tail]=i;
            while(head<tail&&list[head]<i-n+1)head++;
            lie_mn[i][j]=hang_mn[list[head]][j];
        }
    }
    int ans=999999999;
    for(int i=n;i<=a;i++)for(int j=n;j<=b;j++)ans=min(ans,lie_mx[i][j]-lie_mn[i][j]);printf("%d\n",ans);
    return 0;
}

相關文章