#1022 08:50 壁に当たって次の行に行くときの隣り合った数字が星座判定になっているのを修正 #1022 08:50 divmodで座標を復元してマンハッタン距離そのもので判定し直した #とりあえずこれでAC増える、はず〜 h,w,n,d=map(int,input().split()) mh_1=[-w,+w,+1,-1] mh_2=[-w,+w,+1,-1,+2,-2,-2*w,+2*w,-(w-1),-(w+1),+(w-1),+(w+1)] mh_3=[+1,-1,+2,-2,+3,-3,-w,+w,-2*w,+2*w,-3*w,+3*w,-w+1,+w+1,-2*w+1,+2*w+1,-w+2,+w+2,-w-1,+w-1,-2*w-1,+2*w-1,-w-2,+w-2] mh_4=[+1,-1,+2,-2,+3,-3,+4,-4,-w,+w,-2*w,+2*w,-3*w,+3*w,+4*w,-4*w,-w+1,+w+1,-2*w+1,+2*w+1,-w+2,+w+2,-w-1,+w-1,-2*w-1,+2*w-1,-w-2,+w-2,-3*w+1,-2*w+2,-w+3,+w+3,+2*w+2,+3*w+1,-3*w-1,-2*w-2,-w-3,+w-3,+2*w-2,+3*w-1] mh_5=[+1,-1,+2,-2,+3,-3,+4,-4,+5,-5,-w,+w,-2*w,+2*w,-3*w,+3*w,+4*w,-4*w,+5*w,-5*w,-w+1,+w+1,-2*w+1,+2*w+1,-w+2,+w+2,-w-1,+w-1,-2*w-1,+2*w-1,-w-2,+w-2,-3*w+1,-2*w+2,-w+3,+w+3,+2*w+2,+3*w+1,-3*w-1,-2*w-2,-w-3,+w-3,+2*w-2,+3*w-1, -4*w+1,+4*w+1,-4*w-1,+4*w-1,-3*w+2,+3*w+2,-3*w-2,+3*w-2,-2*w+3,+2*w+3,-2*w-3,+2*w-3,-w+4,+w+4,-w-4,+w-4] mh=[mh_1,mh_2,mh_3,mh_4,mh_5] #計算量O(280)? from collections import defaultdict class UnionFind(): def __init__(self, n): self.n = n self.parents = [-1] * n def find(self, x): if self.parents[x] < 0: return x else: self.parents[x] = self.find(self.parents[x]) return self.parents[x] def union(self, x, y): x = self.find(x) y = self.find(y) if x == y: return if self.parents[x] > self.parents[y]: x, y = y, x self.parents[x] += self.parents[y] self.parents[y] = x def size(self, x): return -self.parents[self.find(x)] def same(self, x, y): return self.find(x) == self.find(y) def members(self, x): root = self.find(x) return [i for i in range(self.n) if self.find(i) == root] def roots(self): return [i for i, x in enumerate(self.parents) if x < 0] def group_count(self): return len(self.roots()) def all_group_members(self): group_members = defaultdict(list) for member in range(self.n): group_members[self.find(member)].append(member) return group_members def __str__(self): return '\n'.join(f'{r}: {m}' for r, m in self.all_group_members().items()) class UnionFindLabel(UnionFind): def __init__(self, labels): assert len(labels) == len(set(labels)) self.n = len(labels) self.parents = [-1] * self.n self.d = {x: i for i, x in enumerate(labels)} self.d_inv = {i: x for i, x in enumerate(labels)} def find_label(self, x): return self.d_inv[super().find(self.d[x])] def union(self, x, y): super().union(self.d[x], self.d[y]) def size(self, x): return super().size(self.d[x]) def same(self, x, y): return super().same(self.d[x], self.d[y]) def members(self, x): root = self.find(self.d[x]) return [self.d_inv[i] for i in range(self.n) if self.find(i) == root] def roots(self): return [self.d_inv[i] for i, x in enumerate(self.parents) if x < 0] def all_group_members(self): group_members = defaultdict(list) for member in range(self.n): group_members[self.d_inv[self.find(member)]].append(self.d_inv[member]) return group_members uf = UnionFind(h*w+1) star=[] star_ck=[0]*(h*w+1) for i in range(n): x,y=map(int,input().split()) now=(x-1)*w+y star.append(now) star_ck[now]=1 #星を管理 計算量10**5 + 280? for i in star: for m in mh[d-1]: if i+m < h*w+1 and i+m > 0 and star_ck[i+m] == 1: q1,mod1=divmod(i,w) q2,mod2=divmod(i+m,w) if mod1==0: mod1=w-1 if mod2==0: mod2=w-1 if abs(q1-q2) + abs(mod1-mod2) <= d: uf.union(i,i+m) #星をくっつける n*60 なので最大10**5 * 60 = 10**5 *6 #ここまでで10**5 *6 + 10**2 *3 + 10**5 = 700300 #if文、とりあえずくっつけてるけど範囲外が先に出て怒られそうなら、最初の二つのand条件で分岐させる #最大値:周りで新しい星座を爆誕させられるか +1 or +0 #最小値:周りにどれだけ多い星座があってくっつけられるか -? star_min=0 star_max=0 for i in range(1,h*w): #星がなかったらそこに星を置くと仮定してチェック開始 if star_ck[i]==0: watacco={} #もうくっつけた星座かどうか見た方がいいんじゃないかな〜 now="ONLY" #1つ星同士しかくっつけてないかどうか? for m in mh[d-1]: if i+m < h*w+1 and i+m > 0 and star_ck[i+m] == 1: q1,mod1=divmod(i,w) q2,mod2=divmod(i+m,w) if mod1==0: mod1=w-1 if mod2==0: mod2=w-1 if abs(q1-q2) + abs(mod1-mod2) <= d: #くっつけられる星座(星かも)発見!しました if uf.size(i+m) == 1: #くっつけ先の星が要素1しかないならとりあえずくっつける watacco[i+m]=0 else: now="NO" #くっつけ先がすでに星座なら、増えるパターンないのでONLYを変える roots=uf.find(i+m) #くっつけた星座の根を記録する if roots not in watacco: watacco[roots]=0 if now == "ONLY" and len(watacco) > 0: star_max=1 else: star_min=max(star_min,len(watacco)) check=uf.all_group_members() sign=0 for i in check: if len(check[i]) > 1: sign+=1 if sign==0: print(0,sign+star_max) else: if star_min == 0: print(sign,sign+star_max) else: print(sign-star_min+1,sign+star_max)