結果
問題 | No.2536 同値性と充足可能性 |
ユーザー |
![]() |
提出日時 | 2023-11-13 07:56:08 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 717 ms / 2,000 ms |
コード長 | 27,364 bytes |
コンパイル時間 | 405 ms |
コンパイル使用メモリ | 82,432 KB |
実行使用メモリ | 110,184 KB |
最終ジャッジ日時 | 2024-09-26 03:14:25 |
合計ジャッジ時間 | 8,157 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 31 |
ソースコード
class UnionFind:def __init__(self, n):self.n = nself.parents = [-1] * ndef find(self, x):if self.parents[x] < 0:return xelse: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:returnif self.parents[x] > self.parents[y]:x, y = y, xself.parents[x] += self.parents[y]self.parents[y] = xdef 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_membersdef __str__(self):return "\n".join(f"{r}: {m}" for r, m in self.all_group_members().items())class WeightedUnionFind:def __init__(self, n):self.n = nself.parents = [-1] * nself.diff_weight = [0] * ndef find(self, x):if self.parents[x] < 0:return xelse:r = self.find(self.parents[x])self.diff_weight[x] += self.diff_weight[self.parents[x]]self.parents[x] = rreturn rdef weight(self, x):self.find(x)return self.diff_weight[x]def union(self, x, y, w):w += self.weight(x)w -= self.weight(y)x = self.find(x)y = self.find(y)if x == y:returnif self.parents[x] > self.parents[y]:x, y = y, xw = -wself.parents[x] += self.parents[y]self.parents[y] = xself.diff_weight[y] = wdef diff(self, x, y):return self.weight(x) - self.weight(y)# uf = WeightedUnionFind(N)# uf.union(y,x,z) # Ay = Ax + z# uf.diff(x,y) # Ay-Axを返す# https://raw.githubusercontent.com/shakayami/ACL-for-python/master/segtree.pyclass segtree:n = 1size = 1log = 2d = [0]op = Nonee = 10**15def __init__(self, V, OP, E):self.n = len(V)self.op = OPself.e = Eself.log = (self.n - 1).bit_length()self.size = 1 << self.logself.d = [E for i in range(2 * self.size)]for i in range(self.n):self.d[self.size + i] = V[i]for i in range(self.size - 1, 0, -1):self.update(i)def set(self, p, x):assert 0 <= p and p < self.np += self.sizeself.d[p] = xfor i in range(1, self.log + 1):self.update(p >> i)def get(self, p):assert 0 <= p and p < self.nreturn self.d[p + self.size]def prod(self, l, r):assert 0 <= l and l <= r and r <= self.nsml = self.esmr = self.el += self.sizer += self.sizewhile l < r:if l & 1:sml = self.op(sml, self.d[l])l += 1if r & 1:smr = self.op(self.d[r - 1], smr)r -= 1l >>= 1r >>= 1return self.op(sml, smr)def all_prod(self):return self.d[1]def max_right(self, l, f):assert 0 <= l and l <= self.nassert f(self.e)if l == self.n:return self.nl += self.sizesm = self.ewhile 1:while l % 2 == 0:l >>= 1if not (f(self.op(sm, self.d[l]))):while l < self.size:l = 2 * lif f(self.op(sm, self.d[l])):sm = self.op(sm, self.d[l])l += 1return l - self.sizesm = self.op(sm, self.d[l])l += 1if (l & -l) == l:breakreturn self.ndef min_left(self, r, f):assert 0 <= r and r <= self.nassert f(self.e)if r == 0:return 0r += self.sizesm = self.ewhile 1:r -= 1while r > 1 and (r % 2):r >>= 1if not (f(self.op(self.d[r], sm))):while r < self.size:r = 2 * r + 1if f(self.op(self.d[r], sm)):sm = self.op(self.d[r], sm)r -= 1return r + 1 - self.sizesm = self.op(self.d[r], sm)if (r & -r) == r:breakreturn 0def update(self, k):self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])def __str__(self):return str([self.get(i) for i in range(self.n)])def get_list(self):return [self.get(i) for i in range(self.n)] # オリジナルで追加# RMQのとき# def op(x, y):# return x if x < y else y# seg = segtree([10**9] * N, op, 10**9) # Vの要素とEの値は同じにする #10**9 -> INF# seg.prod(l, r) # op(a[l],...a[r-1])を返す# https://github.com/shakayami/ACL-for-python/blob/master/lazysegtree.pyclass lazy_segtree:def update(self, k):self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])def all_apply(self, k, f):self.d[k] = self.mapping(f, self.d[k])if k < self.size:self.lz[k] = self.composition(f, self.lz[k])def push(self, k):self.all_apply(2 * k, self.lz[k])self.all_apply(2 * k + 1, self.lz[k])self.lz[k] = self.identitydef __init__(self, V, OP, E, MAPPING, COMPOSITION, ID):self.n = len(V)self.log = (self.n - 1).bit_length()self.size = 1 << self.logself.d = [E for i in range(2 * self.size)]self.lz = [ID for i in range(self.size)]self.e = Eself.op = OPself.mapping = MAPPINGself.composition = COMPOSITIONself.identity = IDfor i in range(self.n):self.d[self.size + i] = V[i]for i in range(self.size - 1, 0, -1):self.update(i)# Args:# N (int): 配列の長さ# op (Callable[[S, S], S]): 区間取得に用いる演算# E: 全てのaに対して op(a, e) = a が成り立つ単位元# MAPPING (Callable[[F, S], S]): dataに作用させる関数# COMPOSITION (Callable[[F, F], F]): lazyに作用させる関数 f(g(x))# ID: 全てのaに対して mapping(id, a) = a が成り立つ恒等写像def set(self, p, x):assert 0 <= p and p < self.np += self.sizefor i in range(self.log, 0, -1):self.push(p >> i)self.d[p] = xfor i in range(1, self.log + 1):self.update(p >> i)def get(self, p):assert 0 <= p and p < self.np += self.sizefor i in range(self.log, 0, -1):self.push(p >> i)return self.d[p]def prod(self, l, r):assert 0 <= l and l <= r and r <= self.nif l == r:return self.el += self.sizer += self.sizefor i in range(self.log, 0, -1):if ((l >> i) << i) != l:self.push(l >> i)if ((r >> i) << i) != r:self.push(r >> i)sml, smr = self.e, self.ewhile l < r:if l & 1:sml = self.op(sml, self.d[l])l += 1if r & 1:r -= 1smr = self.op(self.d[r], smr)l >>= 1r >>= 1return self.op(sml, smr)def all_prod(self):return self.d[1]def apply_point(self, p, f):assert 0 <= p and p < self.np += self.sizefor i in range(self.log, 0, -1):self.push(p >> i)self.d[p] = self.mapping(f, self.d[p])for i in range(1, self.log + 1):self.update(p >> i)def apply(self, l, r, f):assert 0 <= l and l <= r and r <= self.nif l == r:returnl += self.sizer += self.sizefor i in range(self.log, 0, -1):if ((l >> i) << i) != l:self.push(l >> i)if ((r >> i) << i) != r:self.push((r - 1) >> i)l2, r2 = l, rwhile l < r:if l & 1:self.all_apply(l, f)l += 1if r & 1:r -= 1self.all_apply(r, f)l >>= 1r >>= 1l, r = l2, r2for i in range(1, self.log + 1):if ((l >> i) << i) != l:self.update(l >> i)if ((r >> i) << i) != r:self.update((r - 1) >> i)def max_right(self, l, g):assert 0 <= l and l <= self.nassert g(self.e)if l == self.n:return self.nl += self.sizefor i in range(self.log, 0, -1):self.push(l >> i)sm = self.ewhile 1:while l % 2 == 0:l >>= 1if not (g(self.op(sm, self.d[l]))):while l < self.size:self.push(l)l = 2 * lif g(self.op(sm, self.d[l])):sm = self.op(sm, self.d[l])l += 1return l - self.sizesm = self.op(sm, self.d[l])l += 1if (l & -l) == l:breakreturn self.ndef min_left(self, r, g):assert 0 <= r and r <= self.nassert g(self.e)if r == 0:return 0r += self.sizefor i in range(self.log, 0, -1):self.push((r - 1) >> i)sm = self.ewhile 1:r -= 1while r > 1 and (r % 2):r >>= 1if not (g(self.op(self.d[r], sm))):while r < self.size:self.push(r)r = 2 * r + 1if g(self.op(self.d[r], sm)):sm = self.op(self.d[r], sm)r -= 1return r + 1 - self.sizesm = self.op(self.d[r], sm)if (r & -r) == r:breakreturn 0# ACLのではない。機能は減るが、こっちのほうが早いclass LazySegTree:def __init__(self, v, op, e, mapping, composition, id_):n = len(v)self._op = opself._e = eself._mapping = mappingself._composition = compositionself._id = id_self._size = 1 << (n - 1).bit_length()self._d = [e] * (2 * self._size)self._lz = [id_] * 2 * self._sizefor i in range(n):self._d[self._size + i] = v[i]for i in range(self._size - 1, 0, -1):self._d[i] = self._op(self._d[2 * i], self._d[2 * i + 1])def _gindex(self, l, r):l += self._sizer += self._sizelm = l >> (l & -l).bit_length()rm = r >> (r & -r).bit_length()while r > l:if l <= lm:yield lif r <= rm:yield rl >>= 1r >>= 1while l:yield ll >>= 1def _propagates(self, *ids):for i in reversed(ids):f = self._lz[i]self._lz[i] = self._idself._lz[2 * i] = self._composition(f, self._lz[2 * i])self._lz[2 * i + 1] = self._composition(f, self._lz[2 * i + 1])self._d[2 * i] = self._mapping(f, self._d[2 * i])self._d[2 * i + 1] = self._mapping(f, self._d[2 * i + 1])def apply(self, l, r, f):(*ids,) = self._gindex(l, r)self._propagates(*ids)l += self._sizer += self._sizewhile l < r:if l & 1:self._lz[l] = self._composition(f, self._lz[l])self._d[l] = self._mapping(f, self._d[l])l += 1if r & 1:self._lz[r - 1] = self._composition(f, self._lz[r - 1])self._d[r - 1] = self._mapping(f, self._d[r - 1])l >>= 1r >>= 1for i in ids:self._d[i] = self._op(self._d[2 * i], self._d[2 * i + 1])def prod(self, l, r):self._propagates(*self._gindex(l, r))resl = self._eresr = self._el += self._sizer += self._sizewhile l < r:if l & 1:resl = self._op(resl, self._d[l])l += 1if r & 1:resr = self._op(self._d[r - 1], resr)l >>= 1r >>= 1return self._op(resl, resr)# RMQのとき# def op(a, b):# if a > b:# return b# return a# def mapping(f, x): # 更新(dataに作用, fは上書きフラグ(f==ID: False))# if f == ID:# return x# return f# def composition(f, g): # 更新(lazyに作用, fは上書きフラグ(f==ID: False), 作用順はg→f)# if f == ID:# return g# return f# ini = INF# ID = ini# lst = lazy_segtree([ini] * len(d), op, ini, mapping, composition, ID)# lst.apply(l, r, x)# lst.prod(l, r)# RAQのとき# def mapping(f, x):# return f + x# def composition(f, g):# return f + g# https://github.com/shakayami/ACL-for-python/blob/master/string.pyclass string:def sa_is(s, upper):n = len(s)if n == 0:return []if n == 1:return [0]if n == 2:if s[0] < s[1]:return [0, 1]else:return [1, 0]sa = [0] * nls = [0] * nfor i in range(n - 2, -1, -1):ls[i] = ls[i + 1] if (s[i] == s[i + 1]) else (s[i] < s[i + 1])sum_l = [0] * (upper + 1)sum_s = [0] * (upper + 1)for i in range(n):if not (ls[i]):sum_s[s[i]] += 1else:sum_l[s[i] + 1] += 1for i in range(upper + 1):sum_s[i] += sum_l[i]if i < upper:sum_l[i + 1] += sum_s[i]def induce(lms):for i in range(n):sa[i] = -1buf = sum_s[:]for d in lms:if d == n:continuesa[buf[s[d]]] = dbuf[s[d]] += 1buf = sum_l[:]sa[buf[s[n - 1]]] = n - 1buf[s[n - 1]] += 1for i in range(n):v = sa[i]if v >= 1 and not (ls[v - 1]):sa[buf[s[v - 1]]] = v - 1buf[s[v - 1]] += 1buf = sum_l[:]for i in range(n - 1, -1, -1):v = sa[i]if v >= 1 and ls[v - 1]:buf[s[v - 1] + 1] -= 1sa[buf[s[v - 1] + 1]] = v - 1lms_map = [-1] * (n + 1)m = 0for i in range(1, n):if not (ls[i - 1]) and ls[i]:lms_map[i] = mm += 1lms = []for i in range(1, n):if not (ls[i - 1]) and ls[i]:lms.append(i)induce(lms)if m:sorted_lms = []for v in sa:if lms_map[v] != -1:sorted_lms.append(v)rec_s = [0] * mrec_upper = 0rec_s[lms_map[sorted_lms[0]]] = 0for i in range(1, m):l = sorted_lms[i - 1]r = sorted_lms[i]end_l = lms[lms_map[l] + 1] if (lms_map[l] + 1 < m) else nend_r = lms[lms_map[r] + 1] if (lms_map[r] + 1 < m) else nsame = Trueif end_l - l != end_r - r:same = Falseelse:while l < end_l:if s[l] != s[r]:breakl += 1r += 1if (l == n) or (s[l] != s[r]):same = Falseif not (same):rec_upper += 1rec_s[lms_map[sorted_lms[i]]] = rec_upperrec_sa = string.sa_is(rec_s, rec_upper)for i in range(m):sorted_lms[i] = lms[rec_sa[i]]induce(sorted_lms)return sadef suffix_array_upper(s, upper):assert 0 <= upperfor d in s:assert 0 <= d and d <= upperreturn string.sa_is(s, upper)def suffix_array(s):n = len(s)if type(s) == str:s2 = [ord(i) for i in s]return string.sa_is(s2, 255)else:idx = list(range(n))idx.sort(key=lambda x: s[x])s2 = [0] * nnow = 0for i in range(n):if i & s[idx[i - 1]] != s[idx[i]]:now += 1s2[idx[i]] = nowreturn string.sa_is(s2, now)def lcp_array(s, sa):n = len(s)assert n >= 1rnk = [0] * nfor i in range(n):rnk[sa[i]] = ilcp = [0] * (n - 1)h = 0for i in range(n):if h > 0:h -= 1if rnk[i] == 0:continuej = sa[rnk[i] - 1]while j + h < n and i + h < n:if s[j + h] != s[i + h]:breakh += 1lcp[rnk[i] - 1] = hreturn lcpdef z_algorithm(s):n = len(s)if n == 0:return []z = [0] * ni = 1j = 0while i < n:z[i] = 0 if (j + z[j] <= i) else min(j + z[j] - i, z[i - j])while (i + z[i] < n) and (s[z[i]] == s[i + z[i]]):z[i] += 1if j + z[j] < i + z[i]:j = ii += 1z[0] = nreturn z# suffix_arrayの作り方# S = "abcababaabc"# sa = string.suffix_array(S)# lcp = string.lcp_array(S, sa)class BIT:def __init__(self, n):self.n = len(n) if isinstance(n, list) else nself.size = 1 << (self.n - 1).bit_length()if isinstance(n, list): # nは1-indexedなリストa = [0]for p in n:a.append(p + a[-1])a += [a[-1]] * (self.size - self.n)self.d = [a[p] - a[p - (p & -p)] for p in range(self.size + 1)]else: # nは大きさself.d = [0] * (self.size + 1)def __repr__(self):p = self.sizeres = []while p > 0:res2 = []for r in range(p, self.size + 1, p * 2):l = r - (r & -r) + 1res2.append(f"[{l}, {r}]:{self.d[r]}")res.append(" ".join(res2))p >>= 1res.append(f"{[self.sum(p + 1) - self.sum(p) for p in range(self.size)]}")return "\n".join(res)def add(self, p, x): # O(log(n)), 点pにxを加算assert p > 0while p <= self.size:self.d[p] += xp += p & -pdef get(self, p, default=None): # O(log(n))assert p > 0return (self.sum(p) - self.sum(p - 1)if 1 <= p <= self.n or default is Noneelse default)def sum(self, p): # O(log(n)), 閉区間[1, p]の累積和assert p >= 0res = 0while p > 0:res += self.d[p]p -= p & -preturn resdef lower_bound(self, x): # O(log(n)), x <= 閉区間[1, p]の累積和 となる最小のpif x <= 0:return 0p, r = 0, self.sizewhile r > 0:if p + r <= self.n and self.d[p + r] < x:x -= self.d[p + r]p += rr >>= 1return p + 1class MultiSet:# n: サイズ、compress: 座圧対象list-likeを指定(nは無効)# multi: マルチセットか通常のOrderedSetかdef __init__(self, n=0, *, compress=[], multi=True):self.multi = multiself.inv_compress = (sorted(set(compress)) if len(compress) > 0 else [i for i in range(n)])self.compress = {k: v for v, k in enumerate(self.inv_compress)}self.counter_all = 0self.counter = [0] * len(self.inv_compress)self.bit = BIT(len(self.inv_compress))def add(self, x, n=1): # O(log n)if not self.multi and n != 1:raise KeyError(n)x = self.compress[x]count = self.counter[x]if count == 0 or self.multi: # multiなら複数カウントできるself.bit.add(x + 1, n)self.counter_all += nself.counter[x] += ndef remove(self, x, n=1): # O(log n)if not self.multi and n != 1:raise KeyError(n)x = self.compress[x]count = self.bit.get(x + 1)if count < n:raise KeyError(x)self.bit.add(x + 1, -n)self.counter_all -= nself.counter[x] -= ndef __repr__(self):return f'MultiSet {{{(", ".join(map(str, list(self))))}}}'def __len__(self): # oprator len: O(1)return self.counter_alldef count(self, x): # O(1)return self.counter[self.compress[x]] if x in self.compress else 0def __getitem__(self, i): # operator []: O(log n)if i < 0:i += len(self)x = self.bit.lower_bound(i + 1)if x > self.bit.n:raise IndexError("list index out of range")return self.inv_compress[x - 1]def __contains__(self, x): # operator in: O(1)return self.count(x) > 0def bisect_left(self, x): # O(log n)return self.bit.sum(bisect.bisect_left(self.inv_compress, x))def bisect_right(self, x): # O(log n)return self.bit.sum(bisect.bisect_right(self.inv_compress, x))# 宣言方法# MultiSet(compress=X,multi=False)# MultiSet(N+1,multi=True)# リストを渡すと座標圧縮して返してくれるdef compress(arr):(*XS,) = set(arr)XS.sort()return {cmp_e: cmp_i for cmp_i, cmp_e in enumerate(XS)}def ctov(c):return ord(c) - ord("a")def CTOV(c):return ord(c) - ord("A")# 約数列挙def make_divisors(n):lower_divisors, upper_divisors = [], []i = 1while i * i <= n:if n % i == 0:lower_divisors.append(i)if i != n // i:upper_divisors.append(n // i)i += 1return lower_divisors + upper_divisors[::-1]# 素因数分解(辞書)def prime_factorize(n):V = defaultdict(int)i = 2while i**2 <= n:while n % i == 0:V[i] += 1n //= ii += 1if n != 1:V[n] += 1return Vdef convert_90(matrix):# 入力行列の行数と列数を取得rows = len(matrix)cols = len(matrix[0])# 90度回転後の行列を初期化rotated_matrix = [[0] * rows for _ in range(cols)]# 元の行列を90度回転させて新しい行列に格納for i in range(rows):for j in range(cols):rotated_matrix[j][rows - 1 - i] = matrix[i][j]return rotated_matrixdef cropping(MAP, mark):M_y, M_x = 0, 0m_y, m_x = INF, INFH, W = len(MAP), len(MAP[0])for i in range(H):for j in range(W):if MAP[i][j] == mark:M_y = max(i, M_y)M_x = max(M_x, j)m_y = min(i, m_y)m_x = min(m_x, j)new = [[0] * (M_x - m_x + 1) for _ in range(M_y - m_y + 1)]for i in range(m_y, M_y + 1):for j in range(m_x, M_x + 1):new[i - m_y][j - m_x] = MAP[i][j]return newdef cos(theta):theta_rad = math.radians(theta)cos_value = math.cos(theta_rad)return cos_valuereturn math.acos(val)def sin(theta):theta_rad = math.radians(theta)sin_value = math.sin(theta_rad)return sin_valuedef acos(value):radians = math.acos(value)degrees = math.degrees(radians)return degrees# ダブリング dp[i][j]:=jから2**i回遷移したときの到達点# https://atcoder.jp/contests/abc167/submissions/40815296# N,K=map(int,input().split())# A=list(map(int,input().split()))# dp=[[-1]*N for _ in range(60)]# for j in range(N):# dp[0][j]=A[j]-1# for i in range(1,60):# for j in range(N):# dp[i][j]=dp[i-1][dp[i-1][j]]# i=0# now=0# while(K>0):# if (K&1)==1:# now=dp[i][now]# i+=1# K>>=1# print(now+1)# 牛ゲー# xj-xi<=bkの条件の下で、xt-xsを最大化する問題# i→jへ、重みbkの有効辺をはったとき、sからtまでの最短距離がxt-xsの最大値と一致する。# 到達できない場合は、xt-xsは無限大from collections import *import sysimport heapqimport bisectimport itertoolsdxdy1 = ((0, 1), (0, -1), (1, 0), (-1, 0))dxdy2 = ((0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (-1, -1), (1, -1), (-1, 1))dxdy3 = ((0, 1), (1, 0))dxdy4 = ((1, 1), (1, -1), (-1, 1), (-1, -1))INF = float("inf")MOD = 998244353mod = 998244353MOD2 = 10**9 + 7mod2 = 10**9 + 7# memo : len([a,b,...,z])==26input = lambda: sys.stdin.readline().rstrip()mi = lambda: map(int, input().split())li = lambda: list(mi())N, M = mi()adj = [[] for _ in range(2 * N)]uf = UnionFind(2 * N)for _ in range(M):x, E, y = map(str, input().split())x, y = int(x), int(y)x -= 1y -= 1if E == "<==>":uf.union(x, y)uf.union(x + N, y + N)adj[x].append(y)adj[y].append(x)adj[x + N].append(y + N)adj[y + N].append(x + N)else:uf.union(x, y + N)uf.union(x + N, y)adj[x].append(y + N)adj[y + N].append(x)adj[x + N].append(y)adj[y].append(x + N)for i in range(N):if uf.same(i, i + N):print("No")exit()visited = [0] * None = []zero = []for i in range(N):if visited[i] == 1:continueone.append(i + 1)visited[i] = 1q = deque()q.append(i)while q:node = q.pop()for nxt in adj[node]:if nxt >= N:if visited[nxt - N] == 1:continuevisited[nxt - N] = 1q.append(nxt)zero.append(nxt - N + 1)else:if visited[nxt] == 1:continuevisited[nxt] = 1q.append(nxt)one.append(nxt + 1)# print(one, zero)print("Yes")if len(one) < (N + 1) // 2:zero.sort()print(len(zero))print(*zero)else:one.sort()print(len(one))print(*one)