CF845E Fire in the City

首先这个答案的值会比较大(\(10^9\) 级别),而枚举答案或者直接计算答案的方式都不可行,于是我们考虑二分答案。

二分答案,那么就只需要判断某个时刻 \(t\) 有没有被覆盖满。

注意到对于每个时刻,此时的图上应该是若干个矩形重叠的样式。注意到 \(n,m\) 很大,不可能存下这些矩形,所以考虑离散化。

离散化完 \(n,m\)\(k\) 的级别。在图上标记原来的 \(k\) 个矩形,每个可能的边长是 \(2t+1\) 的矩形,然后看有没有覆盖所有没有被标记的点。

这是另外一篇题解的思路,好想。反正我是不会写(因为有离散化,后面的操作变得复杂)。

我们不妨来考虑另一种思路。

假设已经标记矩形完成,现在应该是 判断距离最远的两个未标记点的距离是否 \(\le2t\)

要求平面内两点最远距离?直接乱搞。我的方法是按照每个点到原点的距离排序,最后拿前 \(40\) 个点和后 \(40\) 个点的距离取 \(\max\)

离散化是真的挺难写的。。

#import<iostream>
#import<vector>
#import<ranges>
#import<algorithm>

using namespace std;

const int K = 1e3 + 5,S = 2e3 + 5;

int n,m,k,px[K],py[K];
int xl[K],xr[K],yl[K],yr[K];
int X[S],Y[S];
pair<int,int> p[S * S];
bool vis[S][S];

bool chk(int t){
	int lx = 0,ly = 0,lp = 0;
	for(int i = 1;i <= k;++i){
		xl[i] = max(px[i] - t,1);
		xr[i] = min(px[i] + t,n);
		yl[i] = max(py[i] - t,1);
		yr[i] = min(py[i] + t,m);
		X[++lx] = xl[i]; X[++lx] = xr[i];
		Y[++ly] = yl[i]; Y[++ly] = yr[i];
		if(xr[i] != n) X[++lx] = xr[i] + 1;
		if(yr[i] != m) Y[++ly] = yr[i] + 1;
	}
	X[++lx] = 1;
	Y[++ly] = 1; 
	sort(X + 1,X + lx + 1);
	sort(Y + 1,Y + ly + 1);
	lx = unique(X + 1,X + lx + 1) - X - 1;
	ly = unique(Y + 1,Y + ly + 1) - Y - 1;
	for(int i = 1;i <= k;++i){
		xl[i] = prev(upper_bound(X + 1,X + lx + 1,xl[i])) - X;
		xr[i] = prev(upper_bound(X + 1,X + lx + 1,xr[i])) - X;
		yl[i] = prev(upper_bound(Y + 1,Y + ly + 1,yl[i])) - Y;
		yr[i] = prev(upper_bound(Y + 1,Y + ly + 1,yr[i])) - Y;
		for(int x = xl[i];x <= xr[i];++x)
			for(int y = yl[i];y <= yr[i];++y) vis[x][y] = true;
	}
	for(int i = 1;i <= lx;++i)
		for(int j = 1;j <= ly;++j)
			if(vis[i][j]) vis[i][j] = 0;
			else p[++lp] = make_pair(i,j);
	sort(p + 1,p + lp + 1,[](auto a,auto b){
		auto[x0,y0] = a; auto[x1,y1] = b;
		return x0 * y0 != x1 * y1 ? x0 * y0 < x1 * y1 : x0 < y0;
	});
	int dis = 0;
	for(int i = 1;i <= min(40,lp);++i)
		for(int j = max(i,lp - 40);j <= lp;++j){
			auto[xi,yi] = p[i]; auto[xj,yj] = p[j];
			if(xi > xj) swap(xi,xj);
			if(yi > yj) swap(yi,yj);
			xi = X[xi]; xj = xj == lx ? n : X[xj + 1] - 1;
			yi = Y[yi]; yj = yj == ly ? m : Y[yj + 1] - 1;
			dis = max({dis,xj - xi,yj - yi});
		}
	return dis <= (2 * t);
}

int main(){
	cin >> n >> m >> k;
	for(int i = 1;i <= k;++i) cin >> px[i] >> py[i];
	int L = 0,R = max(n,m);
	while(R - L + 1 > 5){
		int mid = (L + R) >> 1;
		chk(mid) ? R = mid : L = mid + 1;
	}
	for(int i = L;i <= R;++i)
		if(chk(i)) return printf("%d\n",i),0;
	return 0;
} 
posted @ 2022-08-05 21:11  One_Zzz  阅读(36)  评论(0)    收藏  举报