freee Programming Contest 2023(AtCoder Beginner Contest 310)G問題メモ

freee Programming Contest 2023(AtCoder Beginner Contest 310)

男子達が水泳をやる会社ではなく、会計管理サービスを中心に提供する会社。

G - Takahashi And Pass-The-Ball Game

問題

  • $N$ 人の人がいて、はじめ、それぞれ $B_1,...,B_N$ 個のボールを持っている
  • 数列 $A=(A_1,...,A_N)$ に従って、「人 $i$ は $A_i$ に自分が持っている全てのボールを渡す」という操作を1回とする
    • ボールは全ての人が同時に渡す
  • この操作を繰り返す回数を $1~K$ から一様ランダムに決める
  • 全ての操作後、各人が持っているボールの個数の期待値を $\mod{998244353}$ で求めよ
  • $1 \le N \le 2 \times 10^5$
  • $1 \le K \le 10^{18}$

解法

求めるのは期待値だが、$K$ で割る前の値である「$1,2,...,K$ 回操作後に渡されるボールの個数の合計」が各人についてわかればよい。

つまり、各頂点 $i$ から $1,...,K$ 回後に訪れる頂点のそれぞれに $B_i$ を加算したい。
もちろんこれを愚直に行うことは時間制約上できない。

$i→A_i$ に辺を張ったグラフはFunctional Graphなので、各連結成分はループが1つとそこに流入する木からなることを利用する。

「ループ上」「木の根に向かうパス上」それぞれにおける区間加算は、累積和を用いて高速化できる。

加算したい頂点がループ上か木上かを区別して、別々に扱うことで実現できる。

ループ上の累積和

ループ上の累積和は、適当な点で切り開いて、「どこから累積和を始めるか」を固定することが重要となる。

その上で、「①最初の周回の末尾まで」「②周回分」「③残り」の3つに分けて加算するとやりやすい。

○→○→●→○→○
        Bi
            + ---- -           ①
+ ---------------- -  x周回分  ②
+ ---- -                       ③

木上の累積和

ループ上の各頂点を根とした木をDFSで辿る。

ループ     r
→○→○→◎→○→○→
          ↑
          ◎
         ↗↖        i
        ○  ◎←◎←●

根 $r$ までのパスを持ちながらDFSする。木上の累積和で加算するのは

  • $i$ のすぐ次の頂点 $A_i$ に $Ans[A_i]+=B_i$
  • $K$ 回目の操作で渡す対象が、まだ根を除く木上かどうかで変化(パスの長さで判断できる)
    • 木上なら、その親頂点を $p$ とし、$Ans[p]-=B_i$
    • ループに入るなら、残り回数($K-$ 根までの距離)だけ、$r$ を始点としてループ上の累積和に加算

このようにし、葉から根に向かって累積和を取っていく($Ans[A_i]+=Ans[i]$)と、 パスへの区間加算を表現できる。

Python3

programming_algorithm/contest_history/atcoder/2023/0715_abc310.txt · 最終更新: 2023/07/26 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0