Game studio "DbZ Games" wants to introduce another map in their popular game "Valiant". This time, the map named "Panvel" will be based on the city of Mumbai.
Mumbai can be represented as n×mn×m cellular grid. Each cell (i,j)(i,j) (1≤i≤n1≤i≤n; 1≤j≤m1≤j≤m) of the grid is occupied by a cuboid building of height ai,jai,j.
This time, DbZ Games want to make a map that has perfect vertical gameplay. That's why they want to choose an l×ll×l square inside Mumbai, such that each building inside the square has a height of at least ll.
Can you help DbZ Games find such a square of the maximum possible size ll?
Input
Each test contains multiple test cases. The first line contains the number of test cases tt (1≤t≤10001≤t≤1000). Description of the test cases follows.
The first line of each test case contains two positive integers nn and mm (1≤n≤m1≤n≤m; 1≤n⋅m≤1061≤n⋅m≤106).
The ii-th of next nn lines contains mm integers ai,1,ai,2,…,ai,mai,1,ai,2,…,ai,m (1≤ai,j≤1061≤ai,j≤106) — heights of buildings on the ii-th row.
It's guaranteed that the sum of n⋅mn⋅m over all test cases doesn't exceed 106106.
Output
For each test case, print the maximum side length ll of the square DbZ Games can choose.
Example
input
4
2 2
2 3
4 5
1 3
1 2 3
2 3
4 4 3
2 1 4
5 6
1 9 4 6 5 8
10 9 5 8 11 6
24 42 32 8 11 1
23 1 9 69 13 3
13 22 60 12 14 17
output
2
1
1
3
题意: 给出一个n*m的矩阵,找出其中最大的一个k*k的子矩阵,满足其中所有的数组都大于等于k。
分析: 很显然可以二分,关键在于判断是否存在满足题意的边长为k的子矩阵。判断的时候可以先扫一遍矩阵,将其中大于k的元素修改为k,然后求二位前缀和,扫描所有边长为k的子矩阵,若其二维区间和大小为k^3,那么就说明存在满足题意的子矩阵。
具体代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#define int long long
using namespace std;
vector<vector<int>> a;
vector<vector<int>> cpy;
vector<vector<int>> s;
int n, m;
bool check(int x){
a = cpy;
s.clear();
for(int i = 0; i <= n; i++){
vector<int> b;
for(int j = 0; j <= m; j++){
b.push_back(0);
if(a[i][j] > x) a[i][j] = x;
}
s.push_back(b);
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
s[i][j] = a[i][j]+s[i-1][j]+s[i][j-1]-s[i-1][j-1];
//枚举左上角位置
for(int i = 1; i+x-1 <= n; i++)
for(int j = 1; j+x-1 <= m; j++){
if(s[i+x-1][j+x-1]-s[i-1][j+x-1]-s[i+x-1][j-1]+s[i-1][j-1] == x*x*x)
return true;
}
return false;
}
signed main(){
int T;
cin >> T;
while(T--){
a.clear();
scanf("%lld%lld", &n, &m);
for(int i = 0; i <= n; i++){
vector<int> b;
b.push_back(0);
if(i == 0)
for(int j = 1; j <= m; j++)
b.push_back(0);
else{
for(int j = 1; j <= m; j++){
int t;
scanf("%d", &t);
b.push_back(t);
}
}
a.push_back(b);
}
cpy = a;
int l = 1, r = min(n, m), ans = -1;
while(l <= r){
int mid = l+r>>1;
if(check(mid)){
ans = mid;
l = mid+1;
}
else r = mid-1;
}
printf("%lld\n", ans);
}
return 0;
}