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;
}

浙公网安备 33010602011771号