zoukankan      html  css  js  c++  java
  • [二维RMQ]luogu 2216 [HAOI2007]理想的正方形

    题目描述

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

    输入输出格式

    输入格式:

    第一行为3个整数,分别表示a,b,n的值

    第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每行相邻两数之间用一空格分隔。

    输出格式:

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

    输入输出样例

    输入样例
    5 4 2
    1 2 5 6
    0 17 16 0
    16 17 2 1
    2 10 2 1
    1 2 2 2
    
    输出样例
    1

    说明

    问题规模

    (1)矩阵中的所有数都不超过1,000,000,000

    (2)20%的数据2<=a,b<=100,n<=a,n<=b,n<=10

    (3)100%的数据2<=a,b<=1000,n<=a,n<=b,n<=100

    分析

    暴力打法显然,设mx[i][j][k]为以i,j为左上角,边长为k的正方形的最大值(最小值同)

    mx[i][j][k]=max(mx[i+1][j+1][k-1],mx[i+1][j][k-1],mx[i][j+1][k-1],rect[i][j])

    然而O(1000^3)显然超

    观察一下,我们发现这个东西很像一个二维的RMQ,那么改一下

    mx[i][j][k]为以i,j为左上角,边长为2^k的正方形的最大值

    mx[i][j][k]=max(mx[i+2^(k-1)][j+2^(k-1)][k-1],mx[i+2^(k-1)][j][k-1],mx[i][j+2^(k-1][k-1],mx[i][j][k-1])

    统计也差不多,注意补一下不满的二进制位和边界

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    const int N=1e3+10;
    int mx[N][N],mn[N][N];
    int a,b,n,logn;
    
    int Get_Ans(int i,int j) {
        int mxx=0,mnn=2147483647;
        mxx=max(mx[i][j],max(mx[i+n-(1<<logn)][j],max(mx[i][j+n-(1<<logn)],mx[i+n-(1<<logn)][j+n-(1<<logn)])));
        mnn=min(mn[i][j],min(mn[i+n-(1<<logn)][j],min(mn[i][j+n-(1<<logn)],mn[i+n-(1<<logn)][j+n-(1<<logn)])));
        return mxx-mnn;
    }
    
    int main() {
        scanf("%d%d%d",&a,&b,&n);
        for (int i=1;i<=a;i++)
            for (int j=1;j<=b;j++) {
                scanf("%d",&mx[i][j]);
                mn[i][j]=mx[i][j];
            }
        logn=log(n)/log(2);
        for (int k=1;k<=logn;k++)
            for (int i=1;i<=a-(1<<k-1);i++)
                for (int j=1;j<=b-(1<<k-1);j++)
                    mx[i][j]=max(mx[i][j],max(mx[i+(1<<k-1)][j],max(mx[i][j+(1<<k-1)],mx[i+(1<<k-1)][j+(1<<k-1)]))),
                    mn[i][j]=min(mn[i][j],min(mn[i+(1<<k-1)][j],min(mn[i][j+(1<<k-1)],mn[i+(1<<k-1)][j+(1<<k-1)])));
        int ans=2147483647;
        for (int i=1;i<=a-n+1;i++)
            for (int j=1;j<=b-n+1;j++)
                ans=min(ans,Get_Ans(i,j));
        printf("%d",ans);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    HTB-靶机-Charon
    第一篇Active Directory疑难解答概述(1)
    Outlook Web App 客户端超时设置
    【Troubleshooting Case】Exchange Server 组件状态应用排错?
    【Troubleshooting Case】Unable to delete Exchange database?
    Exchange Server 2007的即将生命周期,您的计划是?
    "the hypervisor is not running" 故障
    Exchange 2016 体系结构
    USB PE
    10 months then free? 10个月,然后自由
  • 原文地址:https://www.cnblogs.com/mastervan/p/10459022.html
Copyright © 2011-2022 走看看