传送门:CF1731D
题目描述:
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×m cellular grid. Each cell (i,j) (1≤i≤n; 1≤j≤m) of the grid is occupied by a cuboid
building of height ai,j.
This time, DbZ Games want to make a map that has perfect vertical gameplay. That's why they want to choose an l×l
square inside Mumbai, such that each building inside the square has a height of at least l.
Can you help DbZ Games find such a square of the maximum possible size l?
输入:
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
输出:
2
1
1
3
说句实话,赛时感觉这道题比C题要简单.二分+二维前缀和也不难想
主要思路:
- 首先我们把玩一下题面之后应该不难发现我们的 l l l和答案应该是具有单调性的.也就是说我们的 l l l取的越大的话,我们需要满足的区域就越大,需要的数字也就越大,也就越难满足,所以显然是具有二分单调性的
- 然后我们只需要 c h e c k check check函数就行了,对于check函数其实也不难想.刚开始我直接打了一下二维前缀和,然后我想二维前缀和求出一个区间内的所有值,如果区间内的所有值的和大于 m i d ∗ m i d ∗ m i d mid*mid*mid mid∗mid∗mid,就行,然后交上去一个wa.仔细想了一下之后就发现这个是显然不行的.因为存在一个数特别大,其他数可能很小的情况.但是这个想法是可以借鉴的(误打误撞属于是了,笑死我了),我们不能直接记录二维前缀和,但是我们可以记录是否大于mid的二维前缀和情况,也就是说我们将大于等于mid的数记为1.反之记为0.然后我们只需要判断二维前缀和是否大于 m i d ∗ m i d mid*mid mid∗mid就行.这道题的关键部分也就是这一点,至此我们也就解决这道题了
但是这道题对于数组选手来说十分不友好,因为它只给了 n ∗ m n*m n∗m范围的大小,直接使用数组显然爆空间,需要使用 v e c t o r vector vector,对于vector来说,假如我们没有直接给他开辟空间的话,是只能使用 p u s h _ b a c k push\_back push_back进行写入操作的.而且开始位置是0,这就对于二维前缀和来说极不友好.所以我们需要使用 r e s i z e resize resize先进行开辟空间,这样的话我们就可以将其当做数组来用啦
对于resize函数可能会不太熟悉,下面简单介绍一下用法:
动态创建m*n的二维vector
方法一:
vector<vector <int> > nums;
nums.resize(m);
for(int i=0;i<m;i++) nums[i].resize(n);
方法二:
vector<vector <int> > nums;
nums.resize(m,vector<int>(n));
并且注意我们需要先清空再进行开辟,不然会出现奇奇怪怪的问题!!
下面是具体的代码部分:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int t,n,m;
vector<vector<int> >a;
vector<vector<int> >b;
vector<vector<int> >c;
int check(int mid) {
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(a[i][j]>=mid) b[i][j]=1;
else b[i][j]=0;
}
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
c[i][j]=c[i-1][j]+c[i][j-1]-c[i-1][j-1]+b[i][j];
}
}
for(int i=mid;i<=n;i++) {
for(int j=mid;j<=m;j++) {
if(c[i][j]-c[i-mid][j]-c[i][j-mid]+c[i-mid][j-mid]>=mid*mid) return true;
}
}
return false;
}
int main() {
t=read();
while(t--) {
n=read();m=read();
a.clear();b.clear();c.clear();
b.resize(n+3,vector<int>(m+3));
c.resize(n+3,vector<int>(m+3));
a.resize(n+3,vector<int>(m+3));
int l=inf,r=-inf;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
int num=read();
a[i][j]=num;
l=min(l,num);r=max(r,num);
}
}
r=min(r,m);r=min(r,n);l=min(l,r);
int ans=0;
while(l<=r) {
int mid=(l+r)/2;
if(check(mid)) {
l=mid+1;
ans=mid;
}else {
r=mid-1;
}
}
printf("%d\n",ans);
}
return 0;
}