题意:给出一个n阶的方阵,给你一个点,求以这个点为左上角的b*b方阵的最大值和最小值的差值。
三种做法,第一种在求解的过程中记录答案(这应该是叫做记忆化),一种方法是二维RMQ,还有优先队列。
1s内可进行的运算次数约为1e8,记忆化枚举最坏的情况下耗时约为2.5e8,如果数据弱一些就可以划过去了,然后这题还真的过了
#include<cstdio>
int n,b,k,i,j,x,y,maxm,minm,arr[300][300],ans[300][300];
int main(){
scanf("%d%d%d",&n,&b,&k);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&arr[i][j]);
while(k--){
scanf("%d%d",&x,&y);
if(!ans[x][y]){
maxm=0;
minm=0x3f3f3f3f;
for(i=1;i<=b;i++)
for(j=1;j<=b;j++){
if(arr[i+x-1][j+y-1]<minm)minm=arr[i+x-1][j+y-1];
if(arr[i+x-1][j+y-1]>maxm)maxm=arr[i+x-1][j+y-1];
}
ans[x][y]=maxm-minm;
}
printf("%d\n",ans[x][y]);
}
return 0;
}
RMQ模板:(这方法不知道为什么我WA了,所以代码仅供参考qaq)
一维RMQ求得是区间区间的最值,用一个二维数组dq[i][k]来表示以i为左端点的连续2k个数字,即右端点为i+2k-1.则可以将其拆分成两个区间,(i,2k-1-1)和(ik-1,i+2k-1),原区间最大值为这两个区间的最大值,拆分后的区间又可以不断地拆分,直到长度为1
一维RMQ实现
for(int j=1;1<<j<=k;j++){
for(int i=1;i+(1<<j)-1<=k;i++){
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
二维RMQ只是在一维RMQ增加了一位,所以我们用四维数组dp[i][j][k][l]表示以(i,j)为左上角,(i+2k-1,j+2l-1)为右下角的矩阵,和一维RMQ一样,可以将大的矩阵拆分为小的矩阵,不断求出其最大值,直到矩阵为1*1方阵
//这个大家看看就好,我也是做题的时候学的二维RMQ,可能有问题,虽然过了自己的例子,但总归没用这个AC,
for (int j = 0; (1 << j) <=n; j++) {
for (int l = 0; (1<<l) <= n; l++) {
if (l == 0 && j == 0) continue;
for (int row = 1; row + (1 << j) - 1 <= n; row++) {
for (int col = 1; col + (1 << l) - 1 <= n; col++) {
if (j==0) {//当有一维的长度为1是就是一个一维RMQ
max_rix[row][col][j][l] = max(max_rix[row][col + (1 << (l - 1))][j][l - 1], max_rix[row][col][j][l - 1]);
min_rix[row][col][j][l] = min(min_rix[row][col + (1 << (l - 1))][j][l - 1], min_rix[row][col][j][l - 1]);
}
else{
max_rix[row][col][j][l] = max(max_rix[row + (1 << (j - 1))][col][j - 1][l], max_rix[row][col][j - 1][l]);
min_rix[row][col][j][l] = min(min_rix[row + (1 << (j - 1))][col][j - 1][l], min_rix[row][col][j - 1][l]);
}
}
}
}
}
最后是优先队列,用两个单调队列预处理,求出各个b*b矩阵的最大值和最小值,然后询问时直接使用即可,灵感来源与一道求子矩阵最大值和的题
题目链接
我的题解链接
AC代码
#include<cstdio>
#include<deque>
using namespace std;
int qmax[270][270], qmin[270][270], arr[270][270], ansmax[270][270],ansmin[270][270];
struct node {
int id;
int val;
};
int main() {
int n, b, k;
scanf("%d %d %d", &n, &b, &k);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &arr[i][j]);
}
}
for (int i = 1; i <= n; i++) {
deque<node> dqmax, dqmin;
for (int j = 1; j <= n; j++) {
while (!dqmax.empty() && arr[i][j] > dqmax.back().val) dqmax.pop_back();
while (!dqmin.empty() && arr[i][j] < dqmin.back().val) dqmin.pop_back();
while (!dqmax.empty() && j - dqmax.front().id >= b) dqmax.pop_front();
while (!dqmin.empty() && j - dqmin.front().id >= b) dqmin.pop_front();
dqmax.push_back({j,arr[i][j]});
dqmin.push_back({j,arr[i][j]});
if (j >= b) {
ansmax[i][j - b + 1] = dqmax.front().val;
ansmin[i][j - b + 1] = dqmin.front().val;
}
}
}
/*printf("\n");
for (int i = 1; i <= n; i++) {
for (int j = 1; j+b-1 <= n; j++) {
printf("%d ", ansmax[i][j]);
}
printf("\n");
}
printf("\n");*/
for (int i = 1; i <= n; i++) {
deque<node> dqmax, dqmin;
for (int j = 1; j <= n; j++) {
int ma = ansmax[j][i], mi = ansmin[j][i];
while (!dqmax.empty() && ma > dqmax.back().val) dqmax.pop_back();
while (!dqmin.empty() && mi < dqmin.back().val) dqmin.pop_back();
while (!dqmax.empty() && j - dqmax.front().id >= b) dqmax.pop_front();
while (!dqmin.empty() && j - dqmin.front().id >= b) dqmin.pop_front();
dqmax.push_back({j,ma});
dqmin.push_back({j,mi});
if (j >= b) {
ansmax[j-b+1][i] = dqmax.front().val;
ansmin[j-b+1][i] = dqmin.front().val;
}
}
}
/*printf("\n");
for (int i = 1; i+b-1 <= n; i++) {
for (int j = 1; j + b - 1 <= n; j++) {
printf("%d ", ansmax[i][j]);
}
printf("\n");
}
printf("\n");*/
while (k--) {
int l, r;
scanf("%d %d", &l, &r);
printf("%d\n", ansmax[l][r] - ansmin[l][r]);
}
}