3匹の猫

みみねこの競プロ精進メモ

キャディプログラミングコンテスト2021(AtCoder Beginner Contest 193)解法メモ(全問題)

タイトルが長すぎる

リアルタイムで参加できなかったコンテストのブログが抜けてて気になったので、暇なときに解き直してブログを書くことにしました。

A - Discount

算数。割合の計算は比を使った式で書くとわかりやすいと個人的に思う。
A:100 = B:x
と考えてもいいし、
A:B = 100:x
と考えてもいい。どちらにせよ
x = \dfrac{100B}{A}
という式になる。比を使った式の好きなところはこういうところ。

何パーセント引きか聞かれているので、100 - \dfrac{100B}{A}が答え。計算量はO(1)

B - Play Snuke

1軒しかお店が無いとする。このとき、A分かけてお店に着いた時、スヌケマシンの在庫は\max (X-A, 0)である。在庫が1以上のとき、つまりX-A1以上のときに限りP円でスヌケマシンを買うことができる。

お店がN軒に増えた場合でも各店舗での購入条件と購入金額はかわらない。また、どのお店を選んでも、その選択が影響することはないので、スヌケマシンを買うことができるお店のうち一番安く買えるお店での購入金額を求めればよい。計算量はO(N)

C - Unexpressed

事象Aとその余事象A^cの和は全事象\Omegaである。
a^bと表せないもの」 = 「全体」 -a^bと表せるもの」
なので、「a^bと表せるもの」の個数をカウントする。

a^bと表せるもの」の個数を上から評価する(最大値を見積もる)。
aを固定したとき、bを増やすとa^bも増加する。よって、1 \le a^b \le Nを満たすbの個数はb = \log_a Nである。
2 \le bに注意すると、aは最大で\sqrt N程度まで大きくなるので、全体の個数としては\sqrt N \times \log_2 N程度となる。(上から評価しているので、a=2として計算した。)
この値はN=10^5のときでもおよそ1.6 \times 10^6であるため、(a, b)の組を全探索しても実行時間制限に間に合うことがわかった。

カウントするときは重複やオーバーフローに注意して実装する。重複を避けるにはC++のsetなどを用いる。a=\lfloor N \rfloorで探索を打ち切る処理を忘れるとTLEするので注意。計算量はO(\sqrt N \log N)

D - Poker

かなり考えることが多いので順を追って考察する。

まず、「高橋君の勝つ確率」は\dfrac{高橋君が勝つパターンの数}{全てのパターンの数}で求められる。ここで言う「すべてのパターン」とは、すでに表向きになっていて裏向きのカードとして選ばれることのない8枚を除いた9K-8枚から2枚(高橋君の裏向きのカード1枚と青木君の裏向きのカード1枚)を選ぶ方法を指す。よって分母は{}_{9K-8} \mathrm{ C }_2となる。

高橋君に配られた裏向きのカードをx、青木君に配られた裏向きのカードをyと置く。高橋君が勝つパターンの数をカウントしたい。裏向きのカードが何の数かわかれば手札の点数を求めることができるが、ここで9K-8枚の中から2枚選ぶような全探索をするとO(K^2)の計算量となってしまうので実行時間制限に間に合わない。しかし、(x, y)の組み合わせとしては81通りしかないので、xyを決めたとき(x, y)が選ばれるのは何通りか求められれば、高橋君が勝つパターンの数も高速に求められる。

整数iが書かれたカードの残り枚数をC_iとする。x=yなら、C_x枚の中から2枚選ぶので{}_{C_x} \mathrm{C}_2 = C_x(C_x - 1)通りである。x\neq yなら、C_x枚の中から1枚、C_y枚の中から1枚それぞれ選ぶのでC_xC_y通りである。高橋君の手札の点数が青木君の手札の点数より高い場合にこの通り数をそのままカウントに加えることで、確率を求めることができる。

計算量は、手札の枚数をN、カードに書かれた整数の種類数をCとしてO(N+C^3)。この問題ではN=5, C=9であるため十分高速に動作する。

E - Oversleeping

電車の停止する区間は周期的に訪れ、\bmod (2X+2Y)上で一定である。高橋君の起きる区間も同様に、\bmod (P+Q)上で一定である。
ここで、中国剰余定理(CRT)を活用する。この定理は、
aで割るとp余り、bで割るとq余る整数x\bmod (\mathrm{lcm}(a, b))上にちょうど1つだけ存在する」
ということを言っている。さらに、この解となる整数xを構成する効率的なアルゴリズムが知られていて、O(\log(a+b+p+q))で動作する。実装には拡張ユークリッドの互除法を用いることが多いが、atcoder libraryに実装されているcrtをそのまま用いることもできる。

制約より、YQが小さいことがわかる。よって、電車が停止してからi秒後のタイミングと、高橋君が起きてからj秒後のタイミングが初めて一致するときがいくつか求め、(i, j)の組を全探索して最小値を求めればよい。具体的には、以下の2つの合同式を同時に満たす解xの最小値を、0\le i\lt Y, 0\le j\lt Qの範囲で全探索する。

x \equiv X+i \pmod{2X+2Y}
x \equiv P+i \pmod{P+Q}

計算量は、O(YQ\log(X+Y+P+Q))

F - Zebraness

まだ解けていないが、工夫することでフローの問題に帰着できるらしい。

感想

はじめてCRTを学んだが、そこまで難しくなくて食わず嫌いしていたなーと思った。ちなみにCRTは条件式が3本以上あっても解を求めることができる。