結果

問題 No.2251 Marking Grid
ユーザー shobonvipshobonvip
提出日時 2023-03-17 23:09:58
言語 PyPy3
(7.3.15)
結果
TLE  
実行時間 -
コード長 4,885 bytes
コンパイル時間 279 ms
コンパイル使用メモリ 82,788 KB
実行使用メモリ 158,640 KB
最終ジャッジ日時 2024-09-18 12:15:03
合計ジャッジ時間 6,809 ms
ジャッジサーバーID
(参考情報)
judge3 / judge5
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 60 ms
74,916 KB
testcase_01 AC 58 ms
67,480 KB
testcase_02 AC 56 ms
69,508 KB
testcase_03 AC 58 ms
68,580 KB
testcase_04 AC 57 ms
68,488 KB
testcase_05 AC 57 ms
68,184 KB
testcase_06 AC 59 ms
68,880 KB
testcase_07 AC 58 ms
68,244 KB
testcase_08 AC 56 ms
68,532 KB
testcase_09 AC 60 ms
68,552 KB
testcase_10 AC 57 ms
68,592 KB
testcase_11 AC 56 ms
67,864 KB
testcase_12 AC 56 ms
68,356 KB
testcase_13 AC 57 ms
68,808 KB
testcase_14 AC 57 ms
67,948 KB
testcase_15 AC 56 ms
67,788 KB
testcase_16 AC 55 ms
68,132 KB
testcase_17 AC 58 ms
68,792 KB
testcase_18 AC 58 ms
69,004 KB
testcase_19 AC 61 ms
68,388 KB
testcase_20 AC 63 ms
68,664 KB
testcase_21 AC 56 ms
68,192 KB
testcase_22 TLE -
testcase_23 -- -
testcase_24 -- -
testcase_25 -- -
testcase_26 -- -
testcase_27 -- -
testcase_28 -- -
testcase_29 -- -
testcase_30 -- -
testcase_31 -- -
testcase_32 -- -
testcase_33 -- -
testcase_34 -- -
testcase_35 -- -
testcase_36 -- -
testcase_37 -- -
testcase_38 -- -
testcase_39 -- -
testcase_40 -- -
testcase_41 -- -
権限があれば一括ダウンロードができます

ソースコード

diff #

import math
from bisect import bisect_left, bisect_right
from typing import Generic, Iterable, Iterator, TypeVar, Union, List

T = TypeVar('T')

# https://github.com/tatyam-prime/SortedSet/blob/main/SortedSet.py
class SortedSet(Generic[T]):
	BUCKET_RATIO = 50
	REBUILD_RATIO = 170
	
	def _build(self, a=None) -> None:
		"Evenly divide `a` into buckets."
		if a is None: a = list(self)
		size = self.size = len(a)
		bucket_size = int(math.ceil(math.sqrt(size/self.BUCKET_RATIO)))
		self.a = [a[size*i//bucket_size: size*(i+1)//bucket_size] for i in range(bucket_size)]
	
	def __init__(self, a: Iterable[T] = []) -> None:
		"Make a new SortedSet from iterable. / O(N) if sorted and unique / O(N log N)"
		a = list(a)
		if not all(a[i] < a[i+1] for i in range(len(a)-1)):
			a = sorted(set(a))
		self._build(a)
	
	def __iter__(self) -> Iterator[T]:
		for i in self.a:
			for j in i: yield j
	
	def __reversed__(self) -> Iterator[T]:
		for i in reversed(self.a):
			for j in reversed(i): yield j
	
	def __len__(self) -> int:
		return self.size
	
	def __repr__(self) -> str:
		return "SortedSet"+str(self.a)
	
	def __str__(self) -> str:
		s = str(list(self))
		return "{"+s[1: len(s)-1]+"}"
	
	def _find_bucket(self, x: T) -> List[T]:
		"Find the bucket which should contain x. self must not be empty."
		for a in self.a:
			if x <= a[-1]: return a
		return a
	
	def __contains__(self, x: T) -> bool:
		if self.size == 0: return False
		a = self._find_bucket(x)
		i = bisect_left(a, x)
		return i != len(a) and a[i] == x
	
	def add(self, x: T) -> bool:
		"Add an element and return True if added. / O(√N)"
		if self.size == 0:
			self.a = [[x]]
			self.size = 1
			return True
		a = self._find_bucket(x)
		i = bisect_left(a, x)
		if i != len(a) and a[i] == x: return False
		a.insert(i, x)
		self.size += 1
		if len(a) > len(self.a)*self.REBUILD_RATIO:
			self._build()
		return True
	
	def discard(self, x: T) -> bool:
		"Remove an element and return True if removed. / O(√N)"
		if self.size == 0: return False
		a = self._find_bucket(x)
		i = bisect_left(a, x)
		if i == len(a) or a[i] != x: return False
		a.pop(i)
		self.size -= 1
		if len(a) == 0: self._build()
		return True
	
	def lt(self, x: T) -> Union[T, None]:
		"Find the largest element < x, or None if it doesn't exist."
		for a in reversed(self.a):
			if a[0] < x:
				return a[bisect_left(a, x)-1]
	
	def le(self, x: T) -> Union[T, None]:
		"Find the largest element <= x, or None if it doesn't exist."
		for a in reversed(self.a):
			if a[0] <= x:
				return a[bisect_right(a, x)-1]
	
	def gt(self, x: T) -> Union[T, None]:
		"Find the smallest element > x, or None if it doesn't exist."
		for a in self.a:
			if a[-1] > x:
				return a[bisect_right(a, x)]
	
	def ge(self, x: T) -> Union[T, None]:
		"Find the smallest element >= x, or None if it doesn't exist."
		for a in self.a:
			if a[-1] >= x:
				return a[bisect_left(a, x)]
	
	def __getitem__(self, x: int) -> T:
		"Return the x-th element, or IndexError if it doesn't exist."
		if x < 0: x += self.size
		if x < 0: raise IndexError
		for a in self.a:
			if x < len(a): return a[x]
			x -= len(a)
		raise IndexError
	
	def index(self, x: T) -> int:
		"Count the number of elements < x."
		ans = 0
		for a in self.a:
			if a[-1] >= x:
				return ans+bisect_left(a, x)
			ans += len(a)
		return ans
	
	def index_right(self, x: T) -> int:
		"Count the number of elements <= x."
		ans = 0
		for a in self.a:
			if a[-1] > x:
				return ans+bisect_right(a, x)
			ans += len(a)
		return ans

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

mod = 998244353
h,w = map(int,input().split())
a = [list(map(int,input().split())) for i in range(h)]
v = []
for i in range(h):
	for j in range(w):
		v.append((a[i][j] << 30) + (i << 15) + j)
v.sort()

mask = (1 << 15) - 1
x = [0] * h
uf = UnionFind(w)
cnt = w
cnth = h
hr = [SortedSet() for i in range(h)]
ans = 0

v2 = [1] * (h + w + 5)
for i in range(h + w + 4):
	v2[i+1] = v2[i] * 2 % mod

for ty in v[::-1]:
	j = ty & mask
	i = (ty >> 15) & mask
	val = ty >> 30
	tv = cnt + cnth - 2

	mode = 1
	g = hr[i].gt(j)
	if g != None and uf.find(g) == uf.find(j):
		mode = 0
	
	g = hr[i].lt(j)
	if g != None and uf.find(g) == uf.find(j):
		mode = 0
	
	if mode:
		ans += pow(2, tv, mod) * val
		ans %= mod	
	
	if x[i] == 0:
		x[i] = 1
		cnth -= 1
	
	g = hr[i].gt(j)
	if g != None and uf.find(g) != uf.find(j):
		cnt -= 1
		uf.union(g, j)
	
	g = hr[i].lt(j)
	if g != None and uf.find(g) != uf.find(j):
		cnt -= 1
		uf.union(g, j)
	
	hr[i].add(j)

print(ans)
0