Loading [MathJax]/jax/output/CommonHTML/jax.js

AtCoder Regular Contest 174 C,E 問題メモ

AtCoder Regular Contest 174

速解き回のようで速解き回でない、少し速解き回のARC

C - Catastrophic Roulette

問題

  • 1N の目が等確率で出るルーレットがある
  • 先手と後手がゲームをする
    • 交互にルーレットを回す
    • 出た目が初めて出た目なら、罰金なし
    • 出た目が過去に出ていたら、罰金1円支払う
    • 全ての目が出たら終了
  • 先手、後手それぞれが支払う罰金の期待値を、mod998244353 で求めよ
  • 1N106

解法

まだ出てない目が i 個で自分に手番が回ってきたときの、ここからの自分の罰金期待値 Pi、相手の罰金期待値 Qi とする。

最終局面は P0=0,Q0=0 である。

i1i の関係は以下のような式になる。

  • 自分が回して出た目が、初めての目の場合(確率 iN
    • 自分は、相手に i1 個で渡すので、そこからの「相手の相手=自分」の罰金期待値は Qi1
    • 相手は、Pi1
  • 既に出た目の場合(確率 NiN
    • 自分は、罰金1円支払い、相手に i 個で渡す。Qi+1
    • 相手は、Pi

まとめると、

  • Pi=iNQi1+NiN(Qi+1)
  • Qi=iNPi1+NiNPi

ここから、Qi を消すと、PiPi1,Qi1 だけで計算できる式になる。それをもって Qi も計算できる。

i が小さい方から求めていって、PN,QN が答え。

Python3

E - Existence Counting

問題

  • 1,...,N から K 個取り出して並べる」ことで作られうる数列を「よい数列」とする
    • よい数列は NPK 個ある
  • よい数列の1つ P=(P1,...,PK) が与えられる
  • t=1,2,...,N について、以下の条件を満たすよい数列の個数を mod998244353 で求めよ
    • 整数 t が含まれる
    • 辞書順で P 以下である
  • 1KN3×105

解法

P と先頭から比較してはじめて異なる値が出てくる位置を d とする。
桁DPのように、d ごとに分けて考えれば重複を除け、また P より小さい条件を表しやすい。
d には必ず Pd より小さい値が置かれ、その後に置ける数は自由となる。

t を固定すると、条件を満たす数列は以下の3つの場合がある。
tP 中に出てくる位置を u とする。tP 中に出てこない場合、便宜的に u=K とする。

  • t より左で t より大きな値が出現する位置の1つを d とし、Pdt にする
    • d より後に置く数は自由。その個数を数える
  • t または t より左の位置を d とし、Pd を、t 以外の Pd より小さい値にする
    • d より後に置く数は自由となるが、そのうちの1つが t であるものの個数を数える
  • u まで P と一致する
    • 既に t が含まれることは確定。u+1 以降が自由である数列のうち、P 以下の数列の個数を数える
N=18 K=13  t=10 の例
                      u
 i  0  1  2  3  4  5  6  7  8  9 10 11 12
 P  5 13 11  2 18  1 10 15 17  4 12  7  3

①  5 13 11  2 10  x  x  x  x  x  x  x  x
    5 10  x  x  x  x  x  x  x  x  x  x  x    など(xは任意)

②  5  9  x  x  x  x  x  x 10  x  x  x  x
    5 13 11  2 18  1  4  x  x  x 10  x  x    など    

③  5 13 11  2 18  1 10 15  6  x  x  x  x
    5 13 11  2 18  1 10 15 17  4 12  3  x    など

①の個数

上記の例で、d=4 として18を10にした場合、その後に置ける箇所は Kd1=8 個、残る数字は Nd1=13 個ある。

よって、13P8 通りある。

このように、10より左で10より大きい箇所は、d=1,2,4 (Pd=13,11,18) とあるので、合計すると以下の個数分ある。

  • 16P11+15P10+13P8

一般化すると、t より左で、t より大きい値が出現するindexの集合を St として、①に該当する数列は以下の個数存在する。

  • dStNd1PKd1

②の個数

上記の例で、d=1 として、そこを P1=13 より小さい何らかの値に変更したとする。

その後に置ける箇所は Kd1=11 個、残る数字は Nd1=16 個ある。
この中の1つが t である数列の個数を数える。

t を置く場所は11通り、他の箇所の決め方が 15P10 通り。
よって、d=1 の箇所に置く数を1つ決めた場合、以降に10が出てくる数列は、11×15P10 通りある。

一般化すると、以下のようになる。(ただし、Kd2 が負になる場合は 0

  • f(d)=(Kd1)×Nd2PKd2

d の箇所に置ける数の個数分だけ、これが倍加される。

いま、Li を「Pi 未満の数のうち、i より左に出てこない数の個数」と定義する。
たとえば、L6 なら、1,2,5 は P6=10 より小さくて左に出てくるので、それ以外の 6 個が該当する。

d の箇所に置ける数」は、基本的に Ld 個である。ただし、t 自身であってはならないので、tPd の大小関係によって変化する。

  • Pdt の場合、Ld 通りを d に置ける
  • Pd>t の場合、Ld1 通りを d に置ける

このように補正した値を Ld(t) とする。

②に該当する数列は、以下の個数分だけ存在する。

  • ud=0Ld(t)×f(d)

③の個数

tP 中に出てくる場合のみに考慮される。

要は、先頭のいくつかが固定されて、残りが自由である数列の中で、P は何番目ですか、という値となる。

i1 までが固定されて、i 以降が自由であるよい数列の中で P 以下のものの個数を Ri とする。

i=10, Pi=12 の場合
                                 i
i  0  1  2  3  4  5  6  7  8  9 10 11 12    ここまでが固定されて、
P  5 13 11  2 18  1 10 15 17  4 12  7  3    残り3箇所が自由なよい数列の内、
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~           ←P以下のものの個数は?

i に12未満の数を置いて P 未満であることを確定させるか、または12のままにするか。
i に置ける数の個数は、先述の Li と一致する。その後に置く数は自由となる。
12のままにした場合、その個数は Ri+1 と一致する。

まとめると、以下のようになる。

  • Ri=Li×Ni1PKi1+Ri+1

末尾から求めていける。

③に該当する数列は、tP 中に出現する場合、Ru+1 個存在することになる。(出現しない場合は0)

まとめ

t が小さい方から計算する。

①②は、t によって加算される値が異なってくるが、

  • 全て「自分より左の○○の合計」を求める
  • 加算される値は①も②も「Pit の大小関係」に依存する

という性質があるため、Fenwick Tree で、t が小さい方から答えを求めて t の位置を更新していけば、管理できる。

t=1 のとき
i  0  1  2  3  4  5  6  7  8  9 10 11 12    ①: ①の場合の加算分
P  5 13 11  2 18  1 10 15 17  4 12  7  3    ②: ②の場合の加算分,係数 Li-1
  ① ① ① ① ①                            ❷: ②の場合の加算分,係数 Li
  ② ② ② ② ② ❷

t=2 のとき
i  0  1  2  3  4  5  6  7  8  9 10 11 12
P  5 13 11  2 18  1 10 15 17  4 12  7  3
  ① ① ①
  ② ② ② ❷

t=3 のとき
i  0  1  2  3  4  5  6  7  8  9 10 11 12
P  5 13 11  2 18  1 10 15 17  4 12  7  3
  ① ① ①    ①    ① ① ① ① ① ①
  ② ② ② ❷ ② ❷ ② ② ② ② ② ② ❷

t=4 のとき
i  0  1  2  3  4  5  6  7  8  9 10 11 12
P  5 13 11  2 18  1 10 15 17  4 12  7  3
  ① ① ①    ①    ① ① ①
  ② ② ② ❷ ② ❷ ② ② ② ❷

...
  • 初期化
    • ①の個数
      • d=0,...,k1 につき、dNd1PKd1 を加算
    • ②の個数
      • d=0,...,k1 につき、d(Ld1)×(Kd1)×Nd2PKd2 を加算

t の答えを求める際は、t の出現位置を u として、まず自身の箇所を更新する。

  • 更新
    • ①を削除
      • これ以降、t の位置は加算されなくなる
      • u から Nu1PKu1 を減算
    • ②→❷に更新
      • Ld に自身が含まれるため -1 していたものが、しなくてよくなる
      • u(Ku1)×Nu2PKu2 を加算

tP 中に出てこない場合、便宜的に u=K とするが、更新は行わないでよい)

この上で、FenwickTree 上の 0,1,...,u の累積和が①+②の場合、Ru+1 が③の場合に相当する。

O(NlogN) で全ての t に対して求められる。

Python3

programming_algorithm/contest_history/atcoder/2024/0317_arc174.txt · 最終更新: 2024/03/19 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0