Processing math: 100%

AtCoder Beginner Contest 241(Sponsored by Panasonic)D,G問題メモ

D - Sequence Query

問題

  • 空の数列 A がある
  • Q 回、以下のクエリに答えよ
  • クエリの種類
    • 1 x: Ax を追加する
    • 2 x k: Ax 以下の要素のうち、大きい方から k 番目の値を出力する
    • 3 x k: Ax 以上の要素のうち、小さい方から k 番目の値を出力する
  • ただしクエリ2,3の時に該当する値が k 個無かったら -1 と出力する
  • 1Q2×105
  • 1k5

解法

k が小さいので、例えばクエリ2なら「x 以下で最大の値 y と個数を得る」 「y1 以下で最大の値 z と個数を得る」……で k 個に達したらそれが答えとなる。

C++なら、multisetを使えばほぼそのままの関数が用意されているんだけど、 毎度のことながらPythonでは平衡二分探索木がないので、自分で代わりのものを実装する必要がある。

どうやるのが速いんだろうね。Python3でACが早い方から見ていくに、

みたいな感じだった。
まぁ、この辺を把握しておくとよさそう。

また、Binary Indexed Tree や Binary Trie も、 素の状態ではなく、multisetに相当する関数を用意した状態で準備しておくと混乱せず使える。

個数が k に満たないとき用に、番兵として -1 と INF を5個ずつ入れておくと楽。

Python3

G - Round Robin

問題

  • N 人で総当たり戦をする
    • 勝負は必ず決着し、引き分けはない
  • 既に M 試合が終了しており、結果が与えられる
  • 残り試合も行った上で、単独優勝する可能性のある人を全て列挙せよ
  • 2N50

解法

それぞれの人について独立に判定する。

i が単独優勝できるか?
可能性の話なので、残り試合は全て勝つものとして問題ない。

よって、「終了した試合での勝ち数」+「残り試合数」が i の最終的な勝利数 Vi で、 他の人はこれ以上にさせないことができるか?という問題となる。

基本的には、Vi が、他の人の現時点での最大勝利数より大きければよさそうに見える(多く勝ってる人には今後負け続けてもらう)が、 たとえば以下のような場合(AND条件)は、i は単独優勝し得ない。

  • i の最終的な勝利数 Vi=5
  • 既に4勝している人が i 以外に2人いて、その2人はまだ直接対戦してない

終了した試合での勝ち数が多い人は残り試合でなるべく負けてほしいが、 そういう人同士の対戦ではどうしてもどちらかが勝ってしまう。
2人だけならいいが、複数人が絡んできて、またその残り試合も誰と誰は終わった、残っている、がバラバラなので どこから決めれば最適か、一概に決めづらい。

このような問題は、最大流に言い換えられる。

Vi が決まった段階で、それ以外の人につき、「あと何勝まではできる」というのが決まる。

この時点で、i 以外に Vi 以上勝っている人がいれば、i は単独優勝不可能。

それ以外の場合、 「始点 → 人を表す N 頂点 → 残り試合を表す頂点 → 終点」というグラフを作る。(i が勝利すると決めた残り試合は除く)

  • (始点 → 人) には、各人に許される残り勝利数=容量の辺
  • (人 → 試合) には、その人がその試合に出場する場合、容量1の辺
    • この辺に流れる場合、その人がその試合に勝ったことを表現する
  • (試合 → 終点) には、容量1の辺
    • 2人が同時に勝つことはないようにする

を張り、残り試合数分だけの容量を流せれば、i 以外の全員を Vi 未満の勝利数に抑えられる試合結果が存在することになる。

グラフの辺の容量は人によって変化するものの、頂点間の辺の張り方・構造は不変のため、 毎回グラフを作るより、リセット・容量の変更を可能にしておくと、若干速い。

Python3

programming_algorithm/contest_history/atcoder/2022/0226_abc241.txt · 最終更新: 2022/03/04 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0