POJ - 2019 Cornfields

题目链接:https://vjudge.z180.cn/problem/POJ-2019/origin

题意:给定一个n*n的数字矩阵,有q个询问,每次询问以(r,l)为左上角,边长为b的小矩阵中最大与最小值之差。

 

思路:用二维倍增数组解决。

我们考虑一个更一般的,以(r,l)为左上角,长跟宽分别为a,b的矩阵的最值问题。

1.、状态:dp[k1][k2][i][j],表示以(i,j)为左上角,长跟宽长度分别为2^k1,2^k2的矩阵的最值。(下面以最大值为例)

2、状态转移:dp[k1][k2[i][j]=max{dp[k1-1][k2][i][j],dp[k1-1][k2][i-(1<<(k1-1))][j],dp[k1][k2-1][i][j],dp[k1][k2-1][i][j-(1<<(k2-1))]}.

    

3、边界值,初始化。

      memset(dp,-0x3f,sizeof(dp));

      dp[0][0][i][j]=a[i][j];   (1<=i,j<=n)

4、计算答案。

     k1=log(a)/log(2)   k2=log(b)/log(2)

     max{dp[k1][k2][r][l], dp[k1][k2][r+a-(1<<k1)][l], dp[k1][k2][r][l+b-(1<<k2)], dp[k1][k2][[r+a-(1<<k1)][l+b-(1<<k2)]};

 

此题小矩阵的是正方形,所以可以去掉一维。

#include <iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;


int a[255][255],mi[21][255][255],ma[21][255][255],b,n,k,r,l,q;
int solvemax(int r,int l){
    int k=(int)(log(b*1.0)/log(2.0));
    int mx=max(ma[k][r][l],
           max(ma[k][r+b-(1<<k)][l],
           max(ma[k][r][l+b-(1<<k)],ma[k][r+b-(1<<k)][l+b-(1<<k)])));
    return mx;
}

int solvemin(int r,int l){
    int k=(int)(log(b*1.0)/log(2.0));
    int m=min(mi[k][r][l],
           min(mi[k][r+b-(1<<k)][l],
           min(mi[k][r][l+b-(1<<k)],mi[k][r+b-(1<<k)][l+b-(1<<k)])));
    return m;
}
int main()
{
    cin>>n>>b>>q;
    memset(mi,0x3f,sizeof(mi));
    memset(ma,-0x3f,sizeof(ma));
    for(int i=1;i<=n; i++){
       for(int j=1;j<=n;j++){
          cin>>a[i][j];
          mi[0][i][j]=a[i][j];
          ma[0][i][j]=a[i][j];
       }
    }
    for(int k=1; k<21; k++){
            for(int i=1; i+(1<<k)-1<=n; i++){
               for(int j=1;j+(1<<k)-1<=n;j++){
                    mi[k][i][j]=min(mi[k-1][i][j],
                                     min(mi[k-1][i+(1<<(k-1))][j],
                                     min(mi[k-1][i][j+(1<<(k-1))],mi[k-1][i+(1<<(k-1))][j+(1<<(k-1))])));
                   ma[k][i][j]=max(ma[k-1][i][j],
                                     max(ma[k-1][i+(1<<(k-1))][j],
                                     max(ma[k-1][i][j+(1<<(k-1))],ma[k-1][i+(1<<(k-1))][j+(1<<(k-1))])));
               }
            }
    }
    for(int i=1;i<=q; i++){
        cin>>r>>l;
        cout<<solvemax(r,l)-solvemin(r,l)<<endl;
    }
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值