結果
| 問題 | No.3589 Make Ends Meet (Hard) |
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2026-06-13 16:27:47 |
| 言語 | PyPy3 (7.3.17) |
| 結果 |
AC
|
| 実行時間 | 747 ms / 2,000 ms |
| コード長 | 4,946 bytes |
| 記録 | |
| コンパイル時間 | 230 ms |
| コンパイル使用メモリ | 96,108 KB |
| 実行使用メモリ | 176,172 KB |
| 最終ジャッジ日時 | 2026-07-10 21:02:01 |
| 合計ジャッジ時間 | 12,249 ms |
|
ジャッジサーバーID (参考情報) |
judge3_0 / judge1_0 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 47 |
ソースコード
import sys
MOD = 998244353
def solve():
N, M, K = map(int, sys.stdin.read().split())
E = N * (N - 1) // 2
target = E - M
if target < 0:
print(0)
return
Lv = E + 1
NA = N - 2
# 階乗・二項係数
fact = [1] * (E + 1)
for i in range(1, E + 1):
fact[i] = fact[i - 1] * i % MOD
inv_fact = [1] * (E + 1)
inv_fact[E] = pow(fact[E], MOD - 2, MOD)
for i in range(E, 0, -1):
inv_fact[i - 1] = inv_fact[i] * i % MOD
def binom(n, r):
if r < 0 or r > n or n < 0:
return 0
return fact[n] * inv_fact[r] % MOD * inv_fact[n - r] % MOD
# btt[x] = C(x, target)
btt = [binom(x, target) for x in range(Lv)]
def zeros():
return [0] * Lv
def shift_add(dst, src, off, coef):
"""
dst[i + off] += src[i] * coef
"""
if coef == 0 or off >= Lv:
return
n = Lv - off
mod = MOD
# coef = 1 は頻出なので特殊化
if coef == 1:
for i in range(n):
j = i + off
v = dst[j] + src[i]
if v >= mod:
v -= mod
dst[j] = v
# coef = -1 mod MOD も頻出なので特殊化
elif coef == mod - 1:
for i in range(n):
j = i + off
v = dst[j] - src[i]
if v < 0:
v += mod
dst[j] = v
else:
c = coef
for i in range(n):
j = i + off
v = dst[j] + src[i] * c % mod
if v >= mod:
v -= mod
dst[j] = v
def add_vec(dst, src):
mod = MOD
for i in range(Lv):
v = dst[i] + src[i]
if v >= mod:
v -= mod
dst[i] = v
def mul_vec(src, coef):
if coef == 1:
return src[:]
mod = MOD
return [(x * coef) % mod for x in src]
def acc(d, key, vec):
if key in d:
add_vec(d[key], vec)
else:
d[key] = vec
# 無名頂点だけの層を1つ作る
# incoming / return: {(prev, used): vec}
def build_anon(incoming):
done = {}
active = {}
for (p, used), ev in incoming.items():
rem = NA - used
if rem <= 0:
continue
nv = zeros()
shift_add(nv, ev, p, rem % MOD)
shift_add(nv, ev, 0, (MOD - rem) % MOD)
acc(active, (p, used + 1), nv)
j = 1
while active:
nxt = {}
invj = inv_fact[j]
for (p, used), vec in active.items():
acc(done, (j, used), mul_vec(vec, invj))
rem = NA - used
if rem > 0:
nv = zeros()
shift_add(nv, vec, p + j, rem % MOD)
shift_add(nv, vec, j, (MOD - rem) % MOD)
acc(nxt, (p, used + 1), nv)
active = nxt
j += 1
return done
# 層K: 頂点Nを強制配置 + 無名 c 個
def build_K(incoming):
done = {}
active = {}
for (p, used), ev in incoming.items():
nv = zeros()
shift_add(nv, ev, p, 1)
shift_add(nv, ev, 0, MOD - 1)
acc(active, (p, 1, used), nv)
while active:
nxt = {}
for (p, size, used), vec in active.items():
acc(done, (size, used), mul_vec(vec, inv_fact[size - 1]))
rem = NA - used
if rem > 0:
nv = zeros()
shift_add(nv, vec, p + size, rem % MOD)
shift_add(nv, vec, size, (MOD - rem) % MOD)
acc(nxt, (p, size + 1, used + 1), nv)
active = nxt
return done
ans = 0
def finalize(states):
nonlocal ans
for (_p, used), vec in states.items():
u = NA - used
if u < 0:
continue
su = u * (u - 1) // 2
if su >= Lv:
continue
L2 = Lv - su
s = 0
for i in range(L2):
if vec[i]:
s += vec[i] * btt[su + i]
s %= MOD
ans += s
ans %= MOD
e0 = zeros()
e0[0] = 1
cur = {(1, 0): e0} # 層0 = {1}
ok = True
for _ in range(K - 1): # 層 1..K-1
cur = build_anon(cur)
if not cur:
ok = False
break
if ok and cur:
sK = build_K(cur) # 層 K
finalize(sK) # T = K
cur = sK
while cur: # 層 K+1, K+2, ...
cur = build_anon(cur)
if not cur:
break
finalize(cur)
print(ans % MOD)
if __name__ == "__main__":
solve()