ABC020 D - LCM Rush
問題
提出コード(100点)
提出コード(満点)
100点から満点にもっていくことができず、解説を見ました…
言われれば確かにそうだけど~って感じですね。
解法
まずは100点までです。
の制約が少ないので、について何かをするんだろうな、という気持ちになります。
すると、までの数の中を、で割った余りによって分類すると、
そのあまりが等しい数については、最大公約数も等しいことがわかります。
ここで、との最小公倍数は、おなじくとの最大公約数をと表現したとき、
と表すことができます。
ので、で割った余りがとなるような数の総和をもとめ、そこにをかけてあげれば、で割った余りがとなるような数と、の最小公倍数の総和が求められます。
これを、全てのに対して行えば、でこの問題を解くことができます。
で割った余りがとなるような数は、
と表記することができます。
ここで、は以上 (切り捨て)以下の数となります。
とおくと、
で割った余りがとなるような数の総和は、次のような計算式で求められます。
ということで、
をのに対して行えば、答えを求めることができます。で余りをとるタイミングや、割り算のタイミングに気を付けましょう。
ということで、ここまでは今回自分が自力でできた部分です。
ここから先は、素因数分解やらなんやらをするのかなぁと思っていたのですが…
解法自体は解説そのままです。
結局、のパターンは、の約数にしかならないので、~のについて、のパターンによって分けて総和を求め、あとは上と同じようにその総和との積を求めていけば答えが求まる、というものです。
そのために、まずはとなるようなの総和を求める方法を考えてみます。
これは、となるようなの総和を求め、最後に倍したものと同じになります。
この総和は、包除原理を用いると、うまく計算することができます。
を素因数分解し、素因数の種類を洗い出します。今回は、例として3種類の素因数が存在し、だったとします。
このとき、まずは ~ についての総和を求め、そこからとなるようなを引いていくことを考えます。
そして、この後は
- 素因数を奇数種類使用した数の倍数の総和を減算し、偶数種類使用した数の倍数の総和を加算する
という操作を行います。
今回の例だと、およびそれぞれについて、 ~ の中での倍数の総和を求め、減算し、の倍数の総和については加算し直します。また、同じ素因数が2つ以上含まれているような場合(など)は、無視します。
総和を求めるときは、上で行ったような総和の求め方と同じようなことをします。
の倍数は、個(切り捨て)存在するので、これを個としたときに、
という計算をすれば、総和を求めることができます。
また、素因数の種類および、同じ種類の素因数が2つ以上使用されているかどうかは、よくある素因数分解のアルゴリズムを用いれば、容易に調べることができます。
さて、となるようなの総和を求めることができたので、あとは倍すればとなるようなの総和になります。
あとは、全てのについて同じことを繰り返せば終わりです。は、先ほどと同様よくある素因数分解等のアルゴリズムのようなものを使えば、で洗い出すことができます。
ということで、これらの式をバグなく気合で組み立て計算すれば、この問題を解くことができます。
ABC115 D - Christmas
問題
提出コード
まずは、レベルバーガーをすべて食べたときの、食べる全体の枚数および食べるパティの枚数を求めます。
食べる全体の枚数をとすると、
となります。
食べるパティの枚数をとすると、
となります。
初期値は、です。
答えは、再帰によって求めることができます。
レベルバーガーを、下から層食べるときに食べることができるパティの枚数
とします。ここから先は場合分けをして求めます。
のとき
なら答えは1、なら答えは0です(問題の制約により、2以上になることはありません)。上記を除き、のとき
答えは0です。のとき
答えはとなります。上記を除き、のとき
この式が意味するのは、レベルバーガーの半分を食べるかどうか、です。
必ずバーガーは奇数になるので、真ん中のパティの分が+1になっています。
このパターンでは、レベルバーガーを1つと、真ん中のパティを食べることが確定しているので、残りの部分だけ調べればよいです。
ということで、答えはとなります。それ以外、すなわちのとき
一番下にあるバン1枚を食べたら、あとはレベルバーガーを食べる問題に帰着できます。
答えはです。
ということで、上のような再帰関数を作成すれば、答えを求めることができます。
ABC076 D - AtCoder Express
問題
提出コード
終わってから解説を見たのですが、あまりよくわかりませんでした()
解法
実装系だと思います。
まず、加速度は、常に1v/secで増加or減少させて、さっさと目標の速度に直すほうが効率がいいです。
そして、入力がすべて整数なので、この時点で加速度を切り替えるタイミングは、0.5秒単位であることになります(こうなるのは、サンプル4のような、目標の速度に達していないけど切り替えなければならないケースのみです)。
あとは、0秒(スタート)から、最後までの速度を、0.5秒単位で調べます。
まず、全ての時刻について、そのときの速度制限で初期化をしておきます。
は、から秒の間の速度制限だとします。
このとき、から秒の区間以外でも、が影響をおよぼします。
というのも、から秒前だったとき、速度は最大でもしかだせません。同様に、から秒後だったとき、速度はしかだせません。
これを、すべてのについて行い、時刻がのときの速度を求めます。
先ほどの計算を行い、現状の最大速度との最小値で更新していけばよいです。最初と最後は速度が0になっていなければならないことも忘れないようにしましょう。
この更新が終わったら、走った距離を求めます。
秒のときの速度と、その0.5秒後の速度を足し、0.5をかけたあとに2で割ればよいです。
というのも、距離=速度×時間であり、台形(三角形)の面積、つまり(開始時刻の速度+終了時刻の速度)×(走った時間)/2によって求めることができるからです。
これをすべてのについて計算すれば、答えを求めることができます。
0.5秒ごとの速度を記録する場合は、全ての秒数を2倍してあげれば、全部が連続した整数になるので、配列で情報を記録してあげることができます。
ABC021 C - 正直者の高橋くん
問題
提出コード
辺被りを考慮しないコードも提出してみたのですが、どうやらないらしいです
解法
cnt[i] = i番目の町へ行く最短経路の数(で割った余りをとります)
とすると、cnt[b]が答えになります。初期値は、cnt[a]=1です。
あとは、aから幅優先探索をしていけば答えが求まります。
最短距離を記録しておき、今xからyへ向かったとします。
aからyへの最短距離が、xの最短距離+1と等しければ、cnt[y]にcnt[x]を加算していきます。
これを繰り返し、キューの中が空になるまで行えば、答えが求まります。
ある頂点をキューに入れる操作を、間違えて2回以上行わないこと、そしてで割った余りを取り忘れないようにすることを特に注意しましょう。
ABC114 D - 756
問題
提出コード
バグを生やしやすい問題です。相変わらずこういう問題でバグを生やしてしまいます。
解法
をまずは素因数分解し、それぞれの素因数が何回登場しているかを調べます。 これは、それぞれについてで調べることができるので、全体でになります。
素因数分解が完了したら、いよいよ約数が75個になるような数を数え上げていきます。
このような数を作成するには、以下のようなパターンが存在します。
1種類の素因数を74個使用した数
2種類の素因数をそれぞれ2個、24個使用した数
2種類の素因数をそれぞれ4個、14個使用した数
3種類の素因数をそれぞれ3個、5個、5個使用した数
ということで、あとはこれらの条件を満たす個数を数え上げることができれば、答えが求まります。
まずは、の素因数を、登場した回数によって5パターンに分けます。
素因数の個数が74回以上、24以上74未満、14以上24未満、4以上14未満、4未満です。
それぞれをパターン0,1,2,3,4と割り振っていきます。
さて、最初に調べた条件に、これらのパターンを当てはめていきます。
1種類の素因数を74個使用した数
ここに使用できる素因数はパターン0の素因数のみです。
パターン0の個数がそのまま答えになります。2種類の素因数をそれぞれ2個、24個使用した数
前者はすべてのパターン、後者はパターン1もしくは0が使用できます。
前者と後者で使用するパターンが違うときは、それぞれのパターンの個数の積で、同じときは、(使用するパターンの個数)×(使用するパターンの個数-1)で数えることができます。
2個しようするのと、24個使用するのは全く違うものなので、組み合わせではなく順列になります。2種類の素因数をそれぞれ4個、14個使用した数
数え方は上と同様です。使用できるパターンは、前者がパターン0~3、後者が0~2です。3種類の素因数をそれぞれ3個、5個、5個使用した数
このパターンのみ注意が必要です。5個使用する素因数が2つあるので、ここだけ順列ではなく組み合わせを調べる必要があります。
3個使用する素因数はすべてのパターン、5個使用する素因数はパターン4以外が使用できます。
使用するパターンをi,j,kとし、それぞれ3個、5個、5個と割り振ることにします。
ここで場合分けをしていきます。被り防止のため、kはj以上としておきます。
1) i=j=kのとき
(iの個数)×(iの個数-1)×(iの個数-2)/2で求めることができます。
2)i=jのとき、もしくはi=kのとき
(iの個数)×(iの個数-1)×(iとは値が異なる、jもしくはkの個数)となります。
3)それ以外のとき
(iの個数)×(jの個数)×(kの個数)となります。
あとは、これらをすべて全探索して、和を求めれば答えとなります。