AtCoder Regular Contest 115参加記(~C問題)
Aがわからない状態でウンコする最悪ムーブ
A - Two Choices
この問題いつみても解けません。マジで苦手です。解説頑張って書こうとしたけど何もまとまりません。ごめんなさい。
愚直に解こうとするとなので何かしらの工夫が必要というところはわかりました。逆に言うとそれ以外なにもわかってません。(ブログ公開が遅れたのもこの問題のせい)
AtCoderの公式YouTubeチャンネルにあがっているすぬけさんの解説がわかりやすかったですが、あの解説を文章で書けないです。解説目当てで来た人はこちらを見てください。
youtu.be
B - Plus Matrix
100マス計算の内側から外側を復元できるか?という問題。
まずは判定問題を考える。
の各要素が定数だと仮定すると、行列よりも一意に定まる。これを言い換えれば、行列の行目の各要素からを引けば、すべての行はに一致するということである。つまり、もし解を構成できるならば、からまでの増分をとして書き出すと、各行の増分は等しくなる()。逆に、各行の増分が等しいなら、先ほどの議論よりとが存在することが言える。ただしこのままだと負整数も要素に含まれているので、数列の最小値を引いて0以上にする必要がある。
計算量は、。
C - ℕ Coloring
こういう、2つの要素間に条件が発生するような問題は、頂点の無向グラフを考えると良い性質が見えることがある。
番目の頂点に整数を書き込み、がの約数なら頂点とに辺を張る。このとき、問題文の条件は
「辺で結ばれた2頂点に異なる色を塗る必要があるときの、使用する色の数の最小化(とその色の塗り方)」
ということができる。これはグラフの彩色問題と呼ばれる有名な問題だが、NP困難(効率的に解くアルゴリズムが知られていないという意味のはず)の問題である。ということは、辺の貼られ方に特徴があるはずだ。
頂点を最小の正整数である色で塗ることとする。
頂点は他の全ての頂点と隣接しているので、他の頂点が色で塗られることはない。頂点と頂点は隣接していないので、それぞれの頂点を色で塗る。この時、頂点を除くの倍数の頂点は色でも色でも塗れないことがわかる。の倍数に関しても同じ。のべき乗の頂点だけ考えると、頂点は色で、頂点は色で、…という風に、指数の増加に比例して色の種類数も増えていく。
つまり、ある頂点がという風に素因数分解できるとき、頂点の色はであることがわかる。これを以下の整数すべてに対して求めてやればよい。これは例えばエラトステネスの篩を用いた素因数分解などでで解くことができる。
感想
A問題よりB問題やC問題の方が簡単だと思います
AtCoder Beginner Contest 199(Sponsored by Panasonic)参加記(~C問題)
早解きしかできなかった
A - Square Inequality
こういう、一見そのまま解くだけに見える問題を素直に実装すると、たいてい何らかの罠にはまる。たとえば、
- 愚直に計算すると実行時間制限に間に合わない
- 計算途中でオーバーフローする
- 割り算や平方根の計算時に小数の誤差が発生する
- コーナーケースが存在する(0除算など)
などが考えられる。今回は上記のどれにも当てはまらないので、単純に不等式評価を行うだけ。A問題なのでこれでACできる。
計算量は。
B - Intersection
解の候補の最小値は、最大値はであるので、解を全探索して条件を満たすかどうか全探索してカウントする。
計算量は。
ちなみに、別解が存在する。条件式より、解の範囲はとなる。逆に、この範囲にある整数はすべて条件を満たすので、答えはとなる。
こちらの計算量はで、はじめの解法より高速。
C - IPFL
これは、先ほど挙げた罠のうち、「愚直に計算すると実行時間制限に間に合わない」問題。というか競プロの問題の9割がこれである。
クエリの数が最大で個あるため、各クエリに対して高速に回答する必要がある。
クエリでは、文字を交換するだけなので、計算量はである。
クエリでは、長さの文字列を交換するので、計算量はである。
なので例えば、すべてのクエリがクエリだった場合などを考えると、愚直な解法の計算量はとなってしまいTLEする。
ところで、クエリを偶数回連続で処理すると元の文字列に戻る。連続で処理しなくても、クエリで操作されなかった文字に関しては、クエリが偶数回処理されれば元の位置に、奇数回処理されれば位置に移動することがわかる。さらに、クエリを奇数回処理したあとにクエリを処理するのは、クエリでの反転を一度無視して、クエリで与えられた値に対して文字を交換した後にクエリを処理するのと同じである。
つまり、クエリは最後に一度だけ処理すればよく、クエリを処理する時点での「本来何回クエリを処理しているか」がわかれば、全体としての計算量で全てのクエリを処理できる。
感想
Dが難しかった
AtCoder Regular Contest 117参加記(~C問題)
600点問題が解けると嬉しい!!
A - God Sequence
各要素が正の整数である二つの数列を考えることにする。この時、数列の要素の総和と数列の要素の総和が等しくなれば良い。のとき明らかに、とすることで条件を満たすことができる。
(数列より数列の方が長い)と仮定する。(逆ならswapする)
この時数列の要素をとなるように決めると、数列の最後の要素を除いてとし、最後の要素をとすることで条件を満たすことができる。最後の要素で数値を調整するイメージ。
計算量は。
B - ARC Wrecker
階数が同じビルがあった場合、どんな操作をしてもそれらのビルの階数は等しいままである。よって回数が同じビルはひとまとめにしておく。以降、すべてのに重複が無いものとして考える。ついでに数列を昇順に並び替えておく。
として選ぶ数字は数列の要素のどれかとしてよい。また、としたとき、少なくともの値は減るため、は最大でも回しか選べない。
実験するとわかるが、操作の順番は結果に関係しない。つまり「各について、を何回選ぶか」という情報だけわかればよい。さらに、とした場合、を満たすすべてのについて、の値は減る。先ほど昇順にソートした理由はこれで、が小さい順から「何回を選ぶか」を決めていくことで数え上げることができる。
にを回選ぶとすると、とは共にずつ減る。の値が変わらないようなにを選ぶ回数の最大値は、回である。この数値はによらず一定である。
よってが答え。計算量はソートがボトルネックとなり、。
C - Tricolor Pyramid
文字を選ぶ操作をなにかの演算として表現したい。各文字をで置き換えて演算結果を表にまとめる。二つの数をとしたとき、演算結果は と表せる。
左から番目の整数をとすると、最上段の整数に含まれる各の個数は二項係数を用いて表せる。具体的に、最上段の整数はである。なので素直にこの式を計算すればよいが、上のの値を求める方法がわからなかった。
http://www.junko-k.com/collo/collo29.htm
上のサイトを見ながら考えたところ、をで割った余りで場合分けすることでで求められることに気が付いた。なのでその場合分けを丁寧に書いて計算し解答。計算量は。
ちなみにコンテスト後にTwitterを眺めていたところ、この方法は「Lucasの定理」という名前がついていて、進数での各桁の数字をもとにして計算するらしい。コンテスト中に定理を導出した自分すげえ!(素直)
感想
最強学生コンで失ったレートをほとんど取り返したので満足。
第二回日本最強プログラマー学生選手権参加記(~E問題)
脳みそ、うごけー!(動かない)
A - Competition
難しすぎないか…?最初に考えた方針が「両方の肉を同じだけ買ったときの金額で考える」ものだったが上手くいかず、一度B問題を解きに行って戻ってきた。スーパー高橋で売っている肉のgあたりの価格はで求められる。同様に、スーパーすぬけで売っている肉のgあたりの価格は(解であるg当たりの価格をとすると)で求められる。この二つの式の大小関係を式で表すと、
となる。さらに式変形して、
となる。この式の左辺は定数なので、は一通りに定まる。割り算の扱いに注意。計算量は、。
B - Xor of Sequences
制約より、数列に含まれる整数の範囲は以上以下である。この範囲に含まれる整数が解の条件を満たすかを全探索する。
数列に同じ整数が重複することはないという制約があるため、整数をとすると、数列に含まれるの個数がちょうど個なら条件を満たしているといえる。(ちなみにこの処理を、整数を見つけるたびに真理値型のフラグに対してtrueとのXORを取るという処理に変えると、最終的なフラグの値がそのまま解となる。)
これを回繰り返す。計算量は、。
C - Max GCD 2
ユークリッドの互除法での2数の関係から考えてみるとわかりやすい。
整数の最大公約数がであるとき、はともにの倍数である。以上以下の区間内にの倍数が個以上存在すれば、との最大公約数がとなるようなを選ぶことができる。これは、「以上の整数のうちの倍数の最小値」にを加えた値が以下かどうかを判定すればよい。
として考えられる値の最小値は、最大値はであるので、制約よりこれらの間にある整数を全探索しても間に合う。計算量は、。
D - Nowhere P
これ以降の問題は解けていない。
何か簡単な数式で解を表現できるらしいが、そこまで至らなかった。
コンテスト中の方針としては、「とても良い列」ではない列のほうをカウントして全体から引く作戦で考えていたが、数列を重複して数えてしまう沼にハマって抜け出せなかった。
E - Level K Palindrome
レベルの回文として考えられる文字列の長さの最小値を考える。最小の長さを持つレベルの回文は、レベルの回文a
を、間に何も挟まずに組み合わせていくことで作れる。この時の長さは、である。よって、高橋君が持っている文字列の長さをとすると、を満たしている必要がある。ついでにいうとが以上だと確実にimpossible
である。
さらに、レベルの回文を2つのレベルの回文に分解するとき、が偶数なら2分割、が奇数なら間に一文字挟んで2分割、となるしかないので、その文字列を構成するレベル()の回文の長さは一意に定まる。レベルの回文の長さも決まるが、このときどの文字を変えるのが最適なのかがよくわからなかった。レベルの回文は回文であってはいけないという制約が邪魔だった。
感想
レートが50下がって気分も下がったが初めてお酒を飲んで全部忘れたのでOK
AtCoder Beginner Contest 198参加記(~E問題)
コーナーケースに気を付けろ!!
A - Div
A君が得るお菓子の個数を個、B君が得るお菓子の個数を個とすると、という等式が成り立つ。この式から、を固定するとは通りに定まること、がともに正の整数でなければならないことを考えると、が取りうる範囲の中にある整数の個数、つまりが答えとなる。計算量は、。
ちなみに制約がゆるいので、brainfuckでも簡単なif文の処理が書ければ解ける。
B - Palindrome with leading zeros
問題文中の操作は、「を文字列としてみたときの末尾から連続している0
をすべて削除する」と言い換えられる。こうすることで、操作後の文字列が回文かどうかを一度判定するだけで答えが求まる。のときの処理に注意。計算量は。
C - Compass Walking
歩歩くことで、ユークリッド距離が以内の点に移動することができる。また、歩以下で到達できる範囲は、原点から距離が以内の範囲である。このことから、解を二分探索して求めることができる。
ただし、歩歩くことで到達できるのは原点からちょうど離れている点だけであるので、二分探索して得られた解がだった場合にのみ、原点からの距離で場合分けする。
二分探索について。ルートを使うと小数誤差にやられる危険性があるので、整数のまま計算する。具体的には、距離の大小さえわかればよく、距離は負の値を取らないので、距離の2乗をそのまま比較する。式は以下の通り。
また、解の最大値は程度と見積もれるが、距離の2乗で比較する方針だと上式の右辺が最大でとなりオーバーフローするので、二分探索するときの解の最大値はとした。こうすると右辺は単にとなる。計算量は。
コンテスト中はこれで十分だが、より厳密に議論すれば二分探索を用いなくてもで答えを求めることができる(公式解説より)。考察をサボれるときはサボることも大事。
D - Send More Money
条件がごちゃごちゃ書いてあるが、普通に覆面算を解くだけの問題。各英小文字に一桁の整数を割り当てるので、文字の種類数が以上ある場合は解なし。
文字の種類数が以下だった場合、各文字に整数を割り当てる方法を全通り試す。文字の種類数をとすると、通り試せばよいことになる。C++のnext_permutation関数に長さ10の順列を与えてループを回し、順列の先頭個だけをみて実際に文字に割り当て、が成立するか確かめる。計算量は。
E - Unique Color
与えられるグラフは木であるので、頂点間を結ぶパスは必ずつだけ存在する。もちろんそのパスが最短である。また、木の頂点から頂点までのパス上に頂点が含まれていた場合、そのパスに頂点から頂点までのパスが完全に含まれている。
以上のことより、頂点からDFSをして「よい頂点」でない頂点を探すこととする。具体的には、DFSをしながら通った頂点の色をメモしていき、頂点の色がすでに登場しているなら答えから外す、ということをしていけばよい。
メモするための道具として集合(set、挿入・削除がともに)を用いたがTLEしてしまった。setのかわりにunordered_setを使ってみたが変わらず。しかもこの方法はメモリも大量に使うため非常に重い。
もう少し考えると、DFSで戻ってくるとき「どのタイミングで色が使われなくなったか」は「どのタイミングで初めて色が使われたか」の解と等しいため、setを使わず、bool配列で管理することができる。
計算量は、。
F - Cube
むずすぎ
感想
青パフォだったのでうれしいけど、Eでの2ペナがもったいないと思った
キャディプログラミングコンテスト2021(AtCoder Beginner Contest 193)解法メモ(全問題)
タイトルが長すぎる
リアルタイムで参加できなかったコンテストのブログが抜けてて気になったので、暇なときに解き直してブログを書くことにしました。
A - Discount
算数。割合の計算は比を使った式で書くとわかりやすいと個人的に思う。
と考えてもいいし、
と考えてもいい。どちらにせよ
という式になる。比を使った式の好きなところはこういうところ。
何パーセント引きか聞かれているので、が答え。計算量は。
B - Play Snuke
1軒しかお店が無いとする。このとき、分かけてお店に着いた時、スヌケマシンの在庫はである。在庫が以上のとき、つまりが以上のときに限り円でスヌケマシンを買うことができる。
お店が軒に増えた場合でも各店舗での購入条件と購入金額はかわらない。また、どのお店を選んでも、その選択が影響することはないので、スヌケマシンを買うことができるお店のうち一番安く買えるお店での購入金額を求めればよい。計算量は。
C - Unexpressed
事象とその余事象の和は全事象である。
「と表せないもの」 = 「全体」 「と表せるもの」
なので、「と表せるもの」の個数をカウントする。
「と表せるもの」の個数を上から評価する(最大値を見積もる)。
を固定したとき、を増やすとも増加する。よって、を満たすの個数はである。
に注意すると、は最大で程度まで大きくなるので、全体の個数としては程度となる。(上から評価しているので、として計算した。)
この値はのときでもおよそであるため、の組を全探索しても実行時間制限に間に合うことがわかった。
カウントするときは重複やオーバーフローに注意して実装する。重複を避けるにはC++のsetなどを用いる。で探索を打ち切る処理を忘れるとTLEするので注意。計算量は。
D - Poker
かなり考えることが多いので順を追って考察する。
まず、「高橋君の勝つ確率」はで求められる。ここで言う「すべてのパターン」とは、すでに表向きになっていて裏向きのカードとして選ばれることのない枚を除いた枚から枚(高橋君の裏向きのカード枚と青木君の裏向きのカード枚)を選ぶ方法を指す。よって分母はとなる。
高橋君に配られた裏向きのカードを、青木君に配られた裏向きのカードをと置く。高橋君が勝つパターンの数をカウントしたい。裏向きのカードが何の数かわかれば手札の点数を求めることができるが、ここで枚の中から枚選ぶような全探索をするとの計算量となってしまうので実行時間制限に間に合わない。しかし、の組み合わせとしては通りしかないので、とを決めたときが選ばれるのは何通りか求められれば、高橋君が勝つパターンの数も高速に求められる。
整数が書かれたカードの残り枚数をとする。なら、枚の中から枚選ぶので通りである。なら、枚の中から枚、枚の中から枚それぞれ選ぶので通りである。高橋君の手札の点数が青木君の手札の点数より高い場合にこの通り数をそのままカウントに加えることで、確率を求めることができる。
計算量は、手札の枚数を、カードに書かれた整数の種類数をとして。この問題ではであるため十分高速に動作する。
E - Oversleeping
電車の停止する区間は周期的に訪れ、上で一定である。高橋君の起きる区間も同様に、上で一定である。
ここで、中国剰余定理(CRT)を活用する。この定理は、
「で割ると余り、で割ると余る整数は上にちょうど1つだけ存在する」
ということを言っている。さらに、この解となる整数を構成する効率的なアルゴリズムが知られていて、で動作する。実装には拡張ユークリッドの互除法を用いることが多いが、atcoder libraryに実装されているcrt
をそのまま用いることもできる。
制約より、とが小さいことがわかる。よって、電車が停止してから秒後のタイミングと、高橋君が起きてから秒後のタイミングが初めて一致するときがいくつか求め、の組を全探索して最小値を求めればよい。具体的には、以下の2つの合同式を同時に満たす解の最小値を、の範囲で全探索する。
計算量は、。
F - Zebraness
まだ解けていないが、工夫することでフローの問題に帰着できるらしい。
感想
はじめてCRTを学んだが、そこまで難しくなくて食わず嫌いしていたなーと思った。ちなみにCRTは条件式が3本以上あっても解を求めることができる。
AtCoder Regular Contest 116参加記(~C問題)
今回は面白い問題だらけです。あ、既出問題を見つけられるということはその問題の解法を理解しているということだから、そんなに気にすることではないと思います。
A - Odd vs Even
完全既出だったらしい。こんなことがあっていいのか?
いったん制約を無視して愚直に解いてみる。正整数を素因数分解する場合、愚直にまで割っていく方法での計算量となる。約数を列挙する場合、各素因数ごとに何個選ぶかを考える。この時、の素因数にが含まれていた場合、少なくともの約数のうち半分は偶数である。
の例。
さらにの因数にが含まれている場合、の約数のうち半分以上が偶数となる。逆に、の素因数にが含まれていない場合、の約数が偶数となることはない。
よって、をで割った余りとで割った余りを見ることで答えが求まる。今回は大丈夫だが、素因数の話題が出てきたときはやの扱いに注意し、必要なら場合分けして対処する。
計算量は、。
B - Products of Min-Max
整数列は順番を並べ替えても答えに影響しないので、昇順にソートする。こうすると、部分列の最大値と最小値を決めたとき、その間にある各要素に関してに含めても含めなくてもの値は変わらない。の最大値と最小値を全探索すると、計算量はとなる。
さらに、最小値を固定したときの式を書き出してを括り出し、残った部分の式を他の最小値の場合と見比べると、その部分も効率的に更新できることがわかる。詳しい数式は公式解説に載っている。理解したいなら実際に式変形してみるのが早い。
よって、計算量をに削減することができる。
C - Multiple Sequences
解けなかった。公式解説の数え上げによる解法がわかりやすかった。
また、問題文の条件に「」を追加した小問題を考えると、動的計画法+数え上げで解けるらしい。この場合の計算量は?になると思う。
感想
C問題をコンテスト中に解きたかった。解説を読んで理解できたので、まだまだ成長できそう。