题目链接: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;
}