F - Multiplayer Rock-Paper-Scissors

2 secs 1024 MB
kusirakusira's icon kusirakusira

f(g,c,p)f(g, c, p) を、グーが gg 人、チョキが cc 人、パーが pp 人のときの勝ち手(引き分けなら DD)を返す関数とします。この関数自体は O(1)O(1) で計算できます。

クエリ ii について、Li,,RiL_i, \ldots, R_i 番目の人のうち、グーを出した人の人数を gg、チョキを出した人の人数を cc、パーを出した人の人数を pp とします。

あなたがグーを出したときに大人数じゃんけんに勝てるかどうかを考えます。このとき、f(g+1,c,p)f(g + 1, c, p)GG ならば勝つことができます。なぜならば、Li,,RiL_i, \ldots, R_i 番目の人とあなたのうち、グーを出した人の人数は g+1g + 1 人で、チョキ・パーを出した人の人数はそれぞれ ccpp だからです。 同様に、f(g,c+1,p)f(g, c + 1, p)CC ならばチョキを出したときに勝つことができ、f(g,c,p+1)f(g, c, p + 1)PP ならばパーを出したときに勝つことができます。

これより、Li,,RiL_i, \ldots, R_i 番目の人のうち、グー・チョキ・パーをそれぞれ出す人の人数を高速にもとめられればこの問題を解くことができます。これは累積和を使うことで O(1)O(1) で求めることができます。

C++
Python