赛后题解:Codeforces Round #841(Div. 2) CF1731D. Valiant‘s New Map

传送门: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题要简单.二分+二维前缀和也不难想

主要思路:

  1. 首先我们把玩一下题面之后应该不难发现我们的 l l l和答案应该是具有单调性的.也就是说我们的 l l l取的越大的话,我们需要满足的区域就越大,需要的数字也就越大,也就越难满足,所以显然是具有二分单调性的
  2. 然后我们只需要 c h e c k check check函数就行了,对于check函数其实也不难想.刚开始我直接打了一下二维前缀和,然后我想二维前缀和求出一个区间内的所有值,如果区间内的所有值的和大于 m i d ∗ m i d ∗ m i d mid*mid*mid midmidmid,就行,然后交上去一个wa.仔细想了一下之后就发现这个是显然不行的.因为存在一个数特别大,其他数可能很小的情况.但是这个想法是可以借鉴的(误打误撞属于是了,笑死我了),我们不能直接记录二维前缀和,但是我们可以记录是否大于mid的二维前缀和情况,也就是说我们将大于等于mid的数记为1.反之记为0.然后我们只需要判断二维前缀和是否大于 m i d ∗ m i d mid*mid midmid就行.这道题的关键部分也就是这一点,至此我们也就解决这道题了

但是这道题对于数组选手来说十分不友好,因为它只给了 n ∗ m n*m nm范围的大小,直接使用数组显然爆空间,需要使用 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,根据提供的引用内容,我无法理解你具体想要问什么问题。请提供更清晰明确的问题,我将竭诚为你解答。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Codeforces Round 860 (Div. 2)题解](https://blog.csdn.net/qq_60653991/article/details/129802687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [【CodeforcesCodeforces Round 865 (Div. 2) (补赛)](https://blog.csdn.net/t_mod/article/details/130104033)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Codeforces Round 872 (Div. 2)(前三道](https://blog.csdn.net/qq_68286180/article/details/130570952)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值