题目传送门
题目大意:
本题翻译的让很多蒟蒻十分懵逼,我在这里再翻译一下:
一共有t组数据,每组数据都有一个n和m,表示长和宽,再输入一个二维矩阵,之后,你需要选取一个边长为l的正方形,使这里面所有数都大于等于l,求l的最大值。
( 1 <= n, m1≤n≤m ; 1<=n*m≤10^6 )
思路:
本题的数组定义就难倒了很多蒟蒻。因为n*m小于等于1000000,如果都定1000000的话,那么就会MLE,这里有三种解决方案:
1.定一维数组,用的时候在导成二维
2.用vector
3.在C++的高版本中,我们可以定义a[n][m],每次用的时候清空,本蒟蒻用的就是这种。
int a[n+1][m+1];
int z[n+1][m+1];
int b[n+1][m+1];
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
z[i][j]=0;
b[i][j]=0;
}
}
for(int i=0;i<=m;i++){
a[0][i]=0;
}for(int i=1;i<=n;i++){
a[i][0]=0;
}
如果我们一个一个找l肯定会超时,所以我们要使用二分。
那么怎么判断是否合法呢?
我们定义了数组 b和z,我们可以用b来表示某个数是否大于等于l,如果是,那么b[i][j]就为0,否则为1。z是b的前缀和。我们用ans表示答案,初始值为一个极大值,每次和一个区间的z取min,最后看看是不是0就可以了。
代码:
#include<iostream>
#define int long long
using namespace std;
int n,m,k;
signed main(){
cin>>k;
while(k--){
cin>>n>>m;
int a[n+1][m+1];
int z[n+1][m+1];
int b[n+1][m+1];
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
z[i][j]=0;
b[i][j]=0;
}
}
for(int i=0;i<=m;i++){
a[0][i]=0;
}for(int i=1;i<=n;i++){
a[i][0]=0;
}for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}int l=1,r=min(n,m),mid;
while(l<=r){
mid=(l+r)/2;
int sum=2147483647;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]>=mid){
b[i][j]=0;
}else{
b[i][j]=1;
}z[i][j]=z[i-1][j]+z[i][j-1]-z[i-1][j-1]+b[i][j];
}
}
for(int i=1;i<=n-mid+1;i++){
for(int j=1;j<=m-mid+1;j++){
int li=i+mid-1;
int lj=j+mid-1;
sum=min(sum,z[li][lj]-z[i-1][lj]-z[li][j-1]+z[i-1][j-1]);
}
}
if(sum==0){
l=mid+1;
}else{
r=mid-1;
}
}cout<<r<<endl;
}
return 0;
}