結果
問題 | No.2471 Gemini Tree(Ver.Lapislazuli) |
ユーザー | 👑 SPD_9X2 |
提出日時 | 2023-07-19 18:03:35 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 219 ms / 2,000 ms |
コード長 | 4,242 bytes |
コンパイル時間 | 197 ms |
コンパイル使用メモリ | 82,100 KB |
実行使用メモリ | 110,340 KB |
最終ジャッジ日時 | 2024-07-06 14:48:24 |
合計ジャッジ時間 | 6,597 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 59 ms
76,928 KB |
testcase_01 | AC | 59 ms
77,056 KB |
testcase_02 | AC | 59 ms
77,056 KB |
testcase_03 | AC | 59 ms
76,928 KB |
testcase_04 | AC | 59 ms
76,928 KB |
testcase_05 | AC | 60 ms
77,056 KB |
testcase_06 | AC | 70 ms
82,560 KB |
testcase_07 | AC | 61 ms
77,696 KB |
testcase_08 | AC | 59 ms
77,440 KB |
testcase_09 | AC | 82 ms
88,192 KB |
testcase_10 | AC | 84 ms
89,472 KB |
testcase_11 | AC | 82 ms
89,216 KB |
testcase_12 | AC | 83 ms
89,984 KB |
testcase_13 | AC | 61 ms
77,440 KB |
testcase_14 | AC | 60 ms
77,696 KB |
testcase_15 | AC | 61 ms
77,824 KB |
testcase_16 | AC | 59 ms
77,312 KB |
testcase_17 | AC | 59 ms
77,440 KB |
testcase_18 | AC | 60 ms
77,312 KB |
testcase_19 | AC | 60 ms
77,312 KB |
testcase_20 | AC | 60 ms
77,824 KB |
testcase_21 | AC | 61 ms
76,928 KB |
testcase_22 | AC | 61 ms
77,776 KB |
testcase_23 | AC | 197 ms
104,788 KB |
testcase_24 | AC | 200 ms
104,404 KB |
testcase_25 | AC | 202 ms
104,680 KB |
testcase_26 | AC | 207 ms
105,532 KB |
testcase_27 | AC | 197 ms
104,900 KB |
testcase_28 | AC | 219 ms
105,184 KB |
testcase_29 | AC | 194 ms
104,712 KB |
testcase_30 | AC | 212 ms
105,216 KB |
testcase_31 | AC | 205 ms
104,548 KB |
testcase_32 | AC | 169 ms
109,024 KB |
testcase_33 | AC | 165 ms
108,176 KB |
testcase_34 | AC | 164 ms
108,644 KB |
testcase_35 | AC | 183 ms
110,340 KB |
testcase_36 | AC | 191 ms
110,096 KB |
testcase_37 | AC | 200 ms
109,772 KB |
ソースコード
""" Gemini Tree Ver.lapis (4) 想定WA解5 葉を全て含まない条件を落としている かなり強い 落ちなくて困っています… →正しいことが証明できました """ import sys from sys import stdin mod = 998244353 from collections import deque # startからBFS. 距離、親、訪問順を返す def NC_Dij(lis,start): ret = [float("inf")] * len(lis) ret[start] = 0 visit = [] q = deque([start]) plis = [i for i in range(len(lis))] while len(q) > 0: now = q.popleft() visit.append(now) for nex in lis[now]: if ret[nex] > ret[now] + 1: ret[nex] = ret[now] + 1 plis[nex] = now q.append(nex) return ret,plis,visit def modfac(n, MOD): f = 1 factorials = [1] for m in range(1, n + 1): f *= m f %= MOD factorials.append(f) inv = pow(f, MOD - 2, MOD) invs = [1] * (n + 1) invs[n] = inv for m in range(n, 1, -1): inv *= m inv %= MOD invs[m - 1] = inv return factorials, invs def modnCr(n,r): if n < 0 or r < 0 or n < r: return 0 return fac[n] * inv[n-r] * inv[r] % mod fac,inv = modfac(200000,mod) N = int(stdin.readline()) # 制約チェック assert 1 <= N <= 10**5 lis = [ [] for i in range(N) ] for i in range(N-1): u,v = map(int,stdin.readline().split()) u -= 1 v -= 1 lis[u].append(v) lis[v].append(u) # サイズ X の部分木を切り取る方法は何通りあるか? 切り取れる場合、含む葉の個数の最小は? # を計算する _,plis,visit = NC_Dij(lis,0) chnode = [1] * N # 子部分木のサイズ chleaf = [0] * N # 頂点の子部分木の葉の個数 leaf_num = 0 #葉の全体の個数 for i in range(N): if len(lis[i]) == 1: leaf_num += 1 chleaf[i] += 1 for v in reversed(visit): if plis[v] != v: chnode[plis[v]] += chnode[v] chleaf[plis[v]] += chleaf[v] cut_case_num = [0] * (N+1) #サイズXの部分木を切り取る方法は何通りあるか? cut_v = [ None for i in range(N+1) ] #サイズXの部分木を切り取る際のX側の頂点 cut_leaf_min = [float("inf")] * (N+1) #サイズXの部分木を切り取る時、葉の最小個数は? for v in range(N): cut_case_num[chnode[v]] += 1 cut_leaf_min[chnode[v]] = min(cut_leaf_min[chnode[v]] , chleaf[v]) cut_v[chnode[v]] = v cut_case_num[N-chnode[v]] += 1 cut_leaf_min[N-chnode[v]] = min(cut_leaf_min[N-chnode[v]] , leaf_num-chleaf[v]) cut_v[N-chnode[v]] = plis[v] # ここから実際の処理 # G < B を探索 ans = 0 for G in range(N+1): B = N-G if G > B: break elif G == B: if cut_case_num[G] > 0: ans += modnCr(N,G) ans %= mod else: ans += 0 break elif G == 0: #G=0 or B=0 の場合, コーナーとして処理 ans += 2 continue # G < B の場合 if cut_case_num[G] == 0: ans += 0 elif cut_case_num[G] >= 2: ans += 2 * modnCr(N,G) ans %= mod else: # 1通りしか切り方がない場合 leafG = cut_leaf_min[G] leafB = cut_leaf_min[B] # サイズG側の葉に少なくとも1つの緑 or サイズB側の葉に少なくとも1つの青 がある場合 gb_not_eq = 0 # 満たさない場合 if leafG <= B and leafB <= G: gb_not_eq = modnCr(N-leaf_num,B-leafG) ans += 2 * (modnCr(N,G) - gb_not_eq) ans %= mod # 残った gb_not_eq の割当 flag = False # 部分木g側にある青い葉を消す場合→ b側からB-1を取れるか? if len(lis[cut_v[B]]) <= 2: flag = True # 部分木b側にある緑の葉を消す場合→ g側からg-1を取れるか? if len(lis[cut_v[G]]) <= 2: flag = True # 部分木b側にある緑の葉を消す場合→ B側からg-1を取れるか? if cut_case_num[G-1] > 0: # and cut_leaf_min[G-1] < cut_leaf_min[B]: flag = True if flag: ans += 2 * gb_not_eq ans %= mod print (ans % mod)