洛谷 P2216 [HAOI2007]理想的正方形(二维单调队列)
传送门
解题思路
用二维单调队列求出每个 \(n\times n\) 矩形的最大值和最小值。
其实就是先在每一行上做原数组单调队列,再维护每一个行上最大值/最小值所组成的数组的单调队列。
AC代码
(代码写复杂了)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
const int maxn=1005;
int n,a,b,m[maxn][maxn],ans=1e9;
deque<int> q[maxn*2],p[3];
void work(int i,int j,int type){
if(q[i].empty()){
q[i].push_back(j);
return;
}
if(j-q[i].front()>=n) q[i].pop_front();
while(!q[i].empty()&&(m[i-(type==-1?a:0)][q[i].back()]*type<m[i-(type==-1?a:0)][j]*type)) q[i].pop_back();
q[i].push_back(j);
}
void work2(int i,int type){
if(p[type+1].empty()){
p[type+1].push_back(i);
return;
}
if(i-p[type+1].front()>=n) p[type+1].pop_front();
while(!p[type+1].empty()&&(m[i][q[i+(type==-1?a:0)].front()]*type>m[p[type+1].back()][q[p[type+1].back()+(type==-1?a:0)].front()]*type)) p[type+1].pop_back();
p[type+1].push_back(i);
}
int main()
{
ios::sync_with_stdio(false);
cin>>a>>b>>n;
for(int i=1;i<=a;i++){
for(int j=1;j<=b;j++){
cin>>m[i][j];
}
}
for(int j=1;j<=b;j++){
for(int i=1;i<=a;i++){
work(i,j,1);
work(i+a,j,-1);
}
if(j<n) continue;
while(!p[0].empty()) p[0].pop_back();
while(!p[2].empty()) p[2].pop_back();
for(int i=1;i<=a;i++){
work2(i,1);
work2(i,-1);
if(i>=n) ans=min(ans,m[p[2].front()][q[p[2].front()].front()]-m[p[0].front()][q[p[0].front()+a].front()]);
}
}
cout<<ans;
return 0;
}