Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) E. Arson In Berland Forest 二分 前缀和

E. Arson In Berland Forest

The Berland Forest can be represented as an infinite cell plane. Every cell contains a tree. That is, contained before the recent events.

A destructive fire raged through the Forest, and several trees were damaged by it. Precisely speaking, you have a n×m rectangle map which represents the damaged part of the Forest. The damaged trees were marked as "X" while the remaining ones were marked as ".". You are sure that all burnt trees are shown on the map. All the trees outside the map are undamaged.

The firemen quickly extinguished the fire, and now they are investigating the cause of it. The main version is that there was an arson: at some moment of time (let's consider it as 0) some trees were set on fire. At the beginning of minute 0, only the trees that were set on fire initially were burning. At the end of each minute, the fire spread from every burning tree to each of 8 neighboring trees. At the beginning of minute T, the fire was extinguished.

The firemen want to find the arsonists as quickly as possible. The problem is, they know neither the value of T (how long the fire has been raging) nor the coordinates of the trees that were initially set on fire. They want you to find the maximum value of T (to know how far could the arsonists escape) and a possible set of trees that could be initially set on fire.

Note that you'd like to maximize value T but the set of trees can be arbitrary.

Input

The first line contains two integer n and m (1≤n,m≤106, 1≤n⋅m≤106) — the sizes of the map.

Next n lines contain the map. The i-th line corresponds to the i-th row of the map and contains m-character string. The j-th character of the i-th string is "X" if the corresponding tree is burnt and "." otherwise.

It's guaranteed that the map contains at least one "X".

Output

In the first line print the single integer T — the maximum time the Forest was on fire. In the next n lines print the certificate: the map (n×m rectangle) where the trees that were set on fire are marked as "X" and all other trees are marked as ".".

Examples

input
3 6
XXXXXX
XXXXXX
XXXXXX
output
1
......
.X.XX.
......
input
10 10
.XXXXXX...
.XXXXXX...
.XXXXXX...
.XXXXXX...
.XXXXXXXX.
...XXXXXX.
...XXXXXX.
...XXXXXX.
...XXXXXX.
..........
output
2
..........
..........
...XX.....
..........
..........
..........
.....XX...
..........
..........
..........
input
4 5
X....
..XXX
..XXX
..XXX
output
0
X....
..XXX
..XXX
..XXX

题意

现在有个地方发生了火灾,火焰每秒都会往上下左右对角线八个方向进行蔓延。

现在给你最终的火焰图,你想使得燃烧的时间最长,问你最开始的火焰是什么样的。

题解

最暴力的做法是我把当前没燃烧的点加进队列里面,然后每秒用bfs去模拟熄灭的过程。

那么什么时候不能熄灭了呢,就是我熄灭后再蔓延不能得到之前的样子的时候,就是不能再熄灭了。

暴力会T,所以我们得改成二分。

二分+bfs其实也会T,会被卡常数,所以最好改成前缀和的。前缀和的话,火焰从中间向八个方向燃烧,改成向三个方向燃烧的前缀和做法。

具体看代码。

代码

#include<bits/stdc++.h>
using namespace std;

int main() {
	ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int N, M; cin >> N >> M;
	vector<string> G(N);
	for (int i = 0; i < N; i++) {
		cin >> G[i];
	}

	vector<vector<int>> maxSquare(N, vector<int>(M));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if (G[i][j] == '.') maxSquare[i][j] = 0;
			else if (i == 0 || j == 0) {
				maxSquare[i][j] = 1;
			} else {
				maxSquare[i][j] = 1 + min(maxSquare[i-1][j-1], min(maxSquare[i-1][j], maxSquare[i][j-1]));
			}
		}
	}
	vector<vector<int>> coverDist(N, vector<int>(M));
	int mi = 0;
	int ma = int(2e6);
	while (ma - mi > 1) {
		int md = (mi + ma) / 2;
		int s = 2 * md + 1;
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				if (maxSquare[i][j] >= s) {
					coverDist[i][j] = s;
				} else {
					coverDist[i][j] = 0;
				}
			}
		}
		for (int i = N-1; i >= 0; i--) {
			for (int j = M-1; j >= 0; j--) {
				if (i > 0) {
					coverDist[i-1][j] = max(coverDist[i-1][j], coverDist[i][j] - 1);
				}
				if (j > 0) {
					coverDist[i][j-1] = max(coverDist[i][j-1], coverDist[i][j] - 1);
				}
				if (i > 0 && j > 0) {
					coverDist[i-1][j-1] = max(coverDist[i-1][j-1], coverDist[i][j] - 1);
				}
			}
		}
		bool isGood = true;
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				if (G[i][j] == '.') continue;
				if (coverDist[i][j] == 0) isGood = false;
			}
		}
		if (isGood) {
			mi = md;
		} else {
			ma = md;
		}
	}

	cout << mi << '\n';
	int s = 2 * mi + 1;
	vector<string> ans(N, string(M, '.'));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			if (maxSquare[i][j] >= s) {
				ans[i - mi][j - mi] = 'X';
			}
		}
	}
	for (int i = 0; i < N; i++) {
		cout << ans[i] << '\n';
	}

	return 0;
}
posted @   qscqesze  阅读(467)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2016-11-24 Codeforces Round #381 (Div. 1) A. Alyona and mex 构造
2016-11-24 BZOJ 2648: SJY摆棋子 kdtree
2015-11-24 线段树 模板
2015-11-24 Codeforces Round #115 B. Plane of Tanks: Pro 水题
2015-11-24 Codeforces Round #115 A. Robot Bicorn Attack 暴力
点击右上角即可分享
微信分享提示