Atcoder - 129D vector应用

<Atcoder - 129D> vector应用

https://atcoder.jp/contests/abc129/tasks/abc129_d

题意:

给定一个由 和 组成的矩阵,在点处选择一个位置放灯,灯光可以在该点处向上下左右四个方向发射,但是碰到#就停止,问可以被灯光辐射到的最大点数。看下样例1,题意就清楚了,选(2,2)放灯,算上自己最多可以辐射8个点。

思路:

首先看到这种点和#组成的矩阵首先想到深搜和广搜,但是他只有源点是4个方向发射,被源点辐射到的点都是单一方向的,不适合dfs和bfs的使用条件,而且n和m都是2e3搜索可能会TLE,所以这种思路pass。那么接下来会想一种暴力的做法,枚举点的位置,看把当前的点作为放灯的源点,其所在行所在列分别能辐射到多少个点,然后取一个最大值,这样复杂度是n^3的依然会TLE。那么我们想办法优化这种想法,既然碰到#灯光的辐射就停止了,那么我们可以先预处理出#的位置,把第i行的#存进vec[i]中,即vec[i][j]表示第i行第j列是#。这样我们看当前的点在当前行处于哪两个#之间,这就是它水平方向能辐射的点,列方向也是同理。因此我们需要把边界都初始化成#,初始化pos = 0,如下图,(1,1)就是点,那么它处于 vec[1][0] = 0 和 vec[1][1] = 4 这两个#之间,所以它能辐射到的点就是4 - 0 - 1 = 3个。点(1,2)和点(1,3)也是同理,都介于vec[1][0] = 0 和 vec[1][1] = 4 这两个#之间。那么我现在走到(1,4)是#了,那么pos往前前进一位,即pos++,这样我走到(1,5)又是点了,点(1,5)就介于vec[1][1] = 4 和 vec[1][2] = 7之间(这也是我们初始化边界都为#的原因,目的是让每个点都能被两个#夹在中间,这样vec的相邻元素做差就能求出灯光辐射到的点的个数),这样点(1,5)水平方向能辐射到的点就是7 - 4 - 1 = 2个。这是水平方向,竖直方向同理,另一个vector存放第j列的#,依旧每列都先初始化pos = 0,看当前列找到的点在该列中处于那两个#之间。

看下核心代码:

(1) 这步是把#的座标都预处理存进行和列的两个vector中,vec1[i]表示第i行的#的位置,vec2[j]表示第j列的#的位置

for(int i = 0; i <= n + 1; i++) {
	for(int j = 0; j <= m + 1; j++) {
		if(s[i][j] == '#') {
			vec1[i].push_back(j);
			vec2[j].push_back(i);
		}
	}
}

(2) 这步是枚举每行的点,看该行的点介于哪两个#之间

for(int i = 1; i <= n; i++) {
	pos = 0;
	for(int j = 1; j <= m; j++) {
		if(s[i][j] == '.') {
			res[i][j] += vec1[i][pos + 1] - vec1[i][pos] - 1; //相邻两个#之间.的个数
		}
		else pos++;
	}
}

(3) 这步是枚举每列的点,看该列的点介于哪两个#之间

for(int j = 1; j <= m; j++) {
	pos = 0;
	for(int i = 1; i <= n; i++) {
		if(s[i][j] == '.') {
			res[i][j] += vec2[j][pos + 1] - vec2[j][pos] - 1; //相邻两个#之间.的个数
		}
		else pos++;
	}
}

ps:每个点对应的的res[i][j]要减1之后再和ans比较,因为源点这个位置被行列都辐射了一遍,多算了一次。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int maxx = 2e3 + 7;
int n, m, ans;
char s[maxx][maxx];
int res[maxx][maxx];
vector <int> vec1[maxx]; //每行#座标
vector <int> vec2[maxx]; //每列#座标

int main() {
	scanf("%d %d", &n, &m);
	for(int i = 0; i <= n + 1; i++) { //目的是把边界都初始化成#
		for(int j = 0; j <= m + 1; j++) s[i][j] = '#';
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) scanf(" %c", &s[i][j]);
	}
	for(int i = 0; i <= n + 1; i++) {
		for(int j = 0; j <= m + 1; j++) {
			if(s[i][j] == '#') {
				vec1[i].push_back(j);
				vec2[j].push_back(i);
			}
		}
	}
	int pos = 0;
	for(int i = 1; i <= n; i++) {
		pos = 0;
		for(int j = 1; j <= m; j++) {
			if(s[i][j] == '.') {
				res[i][j] += vec1[i][pos + 1] - vec1[i][pos] - 1; //相邻两个#之间.的个数
			}
			else pos++;
		}
	}
	pos = 0;
	for(int j = 1; j <= m; j++) {
		pos = 0;
		for(int i = 1; i <= n; i++) {
			if(s[i][j] == '.') {
				res[i][j] += vec2[j][pos + 1] - vec2[j][pos] - 1; //相邻两个#之间.的个数
			}
			else pos++;
		}
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) ans = max(ans, res[i][j] - 1); //(i, j)位置的点算了两次
	}
	printf("%d\n", ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章