提供一种简介易懂的做法。
首先曼哈顿距离的绝对值比较难处理,所以可以转成切比雪夫距离。
具体地说,就是 \((x,y)\) 变成 \((x+y,x-y)\)(接下来所述的坐标都是变换后的)。
这样 \((x,y),(a,b)\) 之间的距离就是 \(\max\{|a-x|,|b-y|\}\)。
虽然这里还有绝对值,但是这个我们其实是知道大小的,所以并不影响。
接下来考虑怎么构造方案。
由于现在的距离带着 \(\max\),所以考虑判断两点间距离是否 \(\ge d\)。
也就是 \(a-x\ge d\) 或 \(b-y\ge d\),两维分开考虑,这里以 \(x\) 一维为例;
若枚举 \(x\),则只需判断是否存在 \(\ge x+d\) 的 \(a\) 即可。
所以先用 \(O(n+m)\) 次查询,共 \(O(nm)\) 个数,统计出变换后的坐标有无黑点。
再做一次后缀和,然后就直接判断存在 \(\ge k\) 并且不存在 \(\ge k+1\) 即可。
代码
#include<bits/stdc++.h>
void construct_network(int H, int W, int K);
int add_and(std::vector<int> Ns);
int add_or(std::vector<int> Ns);
int add_xor(std::vector<int> Ns);
int add_not(int N);
using namespace std;const int N=2e2+10,M=N*2;
int n,m,k,a[M],b[M],c[M],d[M];vector<int>A[M],B[M];
int chk(int t){//判断两黑点距离是否 >= t
int x=add_or({add_and({a[0],c[t]}),add_and({b[0],d[t]})});
for(int i=1;i+t<k;i++)x=add_or({x,add_and({a[i],c[i+t]})});
for(int i=1;i+t<k;i++)x=add_or({x,add_and({b[i],d[i+t]})});
return x;
}
void construct_network(int H,int W,int K){
n=H;m=W;k=n+m-1;
for(int i=0;i<n;i++)for(int j=0;j<m;j++)A[i+j].push_back(i*m+j);//切比雪夫坐标
for(int i=0;i<n;i++)for(int j=0;j<m;j++)B[i-j+m-1].push_back(i*m+j);
for(int i=0;i<k;i++)a[i]=add_or(A[i]),b[i]=add_or(B[i]);
c[k-1]=a[k-1];for(int i=k-2;i>=0;i--)c[i]=add_or({c[i+1],a[i]});//后缀 or
d[k-1]=b[k-1];for(int i=k-2;i>=0;i--)d[i]=add_or({d[i+1],b[i]});
if(K<k-1)add_and({chk(K),add_not(chk(K+1))});else chk(K);
}
标签:std,IOI2019,--,题解,ge,距离,int,add
From: https://www.cnblogs.com/A-zjzj/p/17046325.html