洛谷P2216 理想的正方形
思路:
直接暴力显然不可行,可以发现每一个矩形向右边扩展时是一列一列增加,于是可以想到单调队列,用数组来维护当前每列的最大值。因为行也有限制,所以还要用一个单调队列来维护行的信息。
做法大概就是每次扩展一行,然后求出每一列当前的最大值,之后再一列一列来搞。
详见代码吧:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1005, M = 105;
int a, b, n;
int mp[N][N], tmp[N][2];
int q1[N][N], l1[N], r1[N], q2[N][N], l2[N], r2[N];
int Q1[N], Q2[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0) ;
cin >> a >> b >> n;
for(int i = 1; i <= a; i++) for(int j = 1; j <= b; j++) cin >> mp[i][j] ;
for(int i = 1; i <= b; i++) l1[i] = l2[i] = 1;
int ans = 2e9;
for(int i = 1; i <= a; i++) {
for(int j = 1; j <= b; j++) {
while(l1[j] <= r1[j] && mp[q1[j][r1[j]]][j] <= mp[i][j]) r1[j]--;
q1[j][++r1[j]] = i ;
while(l2[j] <= r2[j] && mp[q2[j][r2[j]]][j] >= mp[i][j]) r2[j]--;
q2[j][++r2[j]] = i ;
while(l1[j] <= r1[j] && i + 1 - q1[j][l1[j]] > n) l1[j]++;
while(l2[j] <= r2[j] && i + 1 - q2[j][l2[j]] > n) l2[j]++;
}
for(int j = 1; j <= b; j++) tmp[j][0] = mp[q1[j][l1[j]]][j], tmp[j][1] = mp[q2[j][l2[j]]][j];
int mx = 0, mn = 1e9 + 1;
int cc1, cc2;
int L1 = 1, R1 = 0, L2 = 1, R2 = 0;
for(int j = 1; j <= b; j++) {
while(L1 <= R1 && tmp[Q1[R1]][0] <= tmp[j][0]) R1--;
while(L2 <= R2 && tmp[Q2[R2]][1] >= tmp[j][1]) R2--;
Q1[++R1] = j ;
Q2[++R2] = j ;
while(L1 <= R1 && j + 1 - Q1[L1] > n) L1++;
while(L2 <= R2 && j + 1 - Q2[L2] > n) L2++;
if(i >= n && j >= n) ans = min(ans, tmp[Q1[L1]][0] - tmp[Q2[L2]][1]);
// cout << i << ' ' << Q1[L1] << ' ' << Q2[L2] << '\n';
}
// cout << "---------------" << '\n' ;
}
cout << ans;
return 0;
}
/*
5 4 2
1 2 3 4
5 6 7 8
9 8 7 6
1 3 2 3
1 2 3 4
*/