import sys input = sys.stdin.readline MOD = 998244353 # XOR Union-Find class XORUnionFind: def __init__(self, n): self.parent = list(range(n)) self.rank = [0]*n # dist[i]: iとparent[i]を繋ぐエッジのXOR値 self.dist = [0]*n def find(self, x): if self.parent[x] == x: return x px = self.parent[x] self.parent[x] = self.find(px) self.dist[x] ^= self.dist[px] # 経路圧縮時にdistも更新 return self.parent[x] def union(self, x, y, w): # w = dist[x]^dist[y]になるようにx,yを統合 # 既に同じ集合にある場合は一貫性チェック rx = self.find(x) ry = self.find(y) if rx == ry: # 矛盾チェック if (self.dist[x]^self.dist[y]) != w: return False, 0 return True, 0 # unite if self.rank[rx] < self.rank[ry]: rx, ry = ry, rx x, y = y, x self.parent[ry] = rx self.dist[ry] = self.dist[x]^self.dist[y]^w if self.rank[rx] == self.rank[ry]: self.rank[rx] += 1 return True, 1 # 新たな独立制約分、次元が1減る def same(self, x, y): return self.find(x) == self.find(y) def xor_dist(self, x, y): # 同じ集合内でdist[x]^dist[y]を求める if self.find(x) != self.find(y): return None return self.dist[x]^self.dist[y] # 累積用2べきテーブル def precompute_powers_of_two(n, mod): res = [1]*(n+1) for i in range(1, n+1): res[i] = (res[i-1]*2) % mod return res def solve(): H, W = map(int, input().split()) A = [list(map(int, input().split())) for _ in range(H)] cells = [] for i in range(H): for j in range(W): cells.append((A[i][j], i, j)) # ソート cells.sort(key=lambda x:x[0]) # XOR Union-Find 準備 # R[i]:0<=i val=0 ok, dec = xuf.union(r, H+c, 0) if not ok: # 矛盾が生じたら答え0 (問題設定上ないかもしれない) print(0) return dimension -= dec # 独立制約増えたら次元減る # これで「最大値 ≤ val」な良い印付け方の数は2^(dimension)-1(空集合除く) current_count = (pow2[dimension]-1) % MOD diff = (current_count - prev_count) % MOD # diff は「最大値 = val」の印付け方の数 # これに val を掛けて加算 result = (result + val * diff) % MOD prev_count = current_count print(result % MOD) if __name__ == "__main__": solve()