スパークリング黒ココア/ABC282 E - Choose Two and Eat One

Created Sat, 17 Dec 2022 Modified Tue, 26 Sep 2023 09:13:30 +0000

問題

ABC282 E - Choose Two and Eat One

お気持ち

  • ボールがN個あるじゃん?
  • 1回の操作でボール2個取って、1個消して、1個戻すじゃん?
  • 操作の回数はN-1回じゃん?
  • 木っぽくね?
  • この辺から最大全域木までエスパーを受信したかった…
  • このエスパーまで受信できたら、後は割と簡単な問題だったのでは…うーむ、悔しい…
  • 辺の重みを正の値にすると最小全域木、-1倍してあげると最大全域木で取れるね
  • $x^y+y^x$あたりもpowで叩いたら余裕で通ったっぽい…

プリム法

  • 最小全域木を求めるやつ
  • heapq使うよ
  • 適当な頂点1個決めて、その頂点から生えてる辺を全部heapに突っ込む
  • 一番小さい辺と、その先に有る頂点を確定させて、その辺の先にある頂点から生えてる辺も全部heapに突っ込む
  • 後は全頂点が確定するまで木を大きく育てる
    • ダイクストラっぽい
    • こっちのほうが若干効率良いらしい

クラスカル法

  • UnionFind使うよ
  • 辺をコスト順に並べて小さい方から順に見ていく
  • 見てる辺を確定させてた時に閉路ができる?(=辺の両端は同一集合?)
    • Yes→採用しちゃダメだよ
    • No→この辺採用!!!
  • こっちのほうが若干効率悪いっぽい

ソースコード

# UnionFind省略

N, M = map(int, input().split())
A_L = list(map(int, input().split()))

edge_L = []

for a in range(N - 1):
    for b in range(a + 1, N):
        x = A_L[a]
        y = A_L[b]
        score = pow(pow(x, y, M) + pow(y, x, M), 1, M)
        edge_L.append((-score, a, b))

edge_L.sort()
uf = UnionFind(N)
ans = 0

for score, a, b in edge_L:
    if not uf.same(a, b):
        uf.union(a, b)
        ans += -score

print(ans)