ABC174に出たので、考えたことを整理してみる。

スポンサードリンク



こんにちは。ふぁんたです。



2020年8月2日のABC174に参加しました。



どういうふうに考えて、どういった実装をしたのか、

自分の頭の中の整理を兼ねて、書き出してみようと思います。







C - Repsept


C-Repsept

問題概要


Kが与えられます。

7,77,777,7777,77777 と7が増えていく数列について、Kの倍数が初めて出てくるのはいつですか?



制約として、\\(K \\leq 2 \\times 10^6\\)


考えたこと


・愚直にやってしまうと、すぐにオーバーフローしてしまいそう



→999983の入力例があり、7が90万個続く数字は流石によくないので。







・数列の実装方法は、「前のやつに10かけて7足す」をやればできそう。





・ある数字Aに10かけて7足した数をKで割ったあまりは、

AをKで割ったあまりに10かけて7足すのと同じ。





→ なら、7を増やす操作をするたびにKで割った余りを取るようにすれば、捜査する数字がKより大きくなることはない



ということに気づけば、実装ができる。




D - Alter Altar


D - Alter Altar

問題概要


RとWからなる文字列があります。





・RをWにする操作

・WをRにする操作

・好きな文字2つを入れ替える操作

ができます。





「Wの右にRがある」という状態を避ける文字列にするために、最低何回の操作が必要ですか?

\\(2 \\leq N \\leq 2 \\times 10^5\\)




考えたこと




1.全部Wにすればいい。



2.全部Rにしてもいい。



…このどちらかで、手数が少ない方では?





→という思いを打ち壊してくれたのが、入力例3です。
8

WRWWRWRR



Wは4つ、Rも4つなのに、出力は3。



「入れ替えを上手いこと使えば、全部いっしょの文字にしなくてもいいよ」

ということを言いたいがための入力例なんだと思います。





そこで、左側にR、右側にWを集めてしまえば、「WR」という文字列はなくなるので、

そうなるようにシミュレートすると、この入力例では3になりました。





なので、



1.右からRを探す。左から探している探索範囲に踏み込むか、探索範囲が文字列を超えたら終了。



2.左からWを探す。右から探している探索範囲に踏み込むか、探索範囲が文字列を超えたら終了。



3.両方見つかったら必要な操作数を1足して、その内側から探索をする(1に戻る)





をすればよいな、とわかりました。









ちなみに、Alter Altarという問題名ですが、



Alter…変える者

Altar…祭壇



という意味です。祭壇に供えられた石の色を変えるからですね。


E - logs


E - logs

問題概要




N本の丸太があります。K回まで切ることができ、その丸太たちの中で最も長いやつの長さを最小にしたいです。

最小で長さはいくつになりますか?



\\(丸太の本数 \\leq 2 \\times 10^5\\)

\\(切れる回数 \\leq 10^9\\)

\\(初期状態の各丸太の長さ \\leq? 10^9\\)


考えたこと






(間違った判断をしました。)

・切るべき丸太は最も長いやつで確定。



・それを半分にするという操作をしていけば、最小の長さは求まる。



・使うべきはPriority Queueで、実際にシミュレートして答えを出せば良い。



→ 切れる回数Kは\\(10^9\\)まであるので、絶対に間に合わない。

また、半分にするのが最適というわけでもない。その反例は入力例1である。







(ここから正しい判断でした)



・「最大」の丸太を「最小」化する問題 なので、二分探索を使うだろう。



「全ての丸太の長さをX以下にすることは、カットK回以内でできるか?」という関数で二分探索を行えば良い。







・探索範囲が十分小さくなれば探索を打ち切る。

ただし、「4.9999にはできないけど、5.000001にはできるよ!」といったような場合、愚直にCeilingしてしまうと6を出力する。



→これを避けるため、出力予定の値をFloorした値を突っ込んで、達成できるかどうかを見る。

(この時彼は知る由もなかった この実装が大きくバグり散らかすことになろうとは)







注意点が2つ。



・まず、「切る回数を間違えないこと」。



長さ5の木を、長さ5以下にするために必要なカット回数は0です。



余りを計算しておいて、余りが0ならカット回数を1減らす、としましょう。





・次に、「出力予定の値をFloorした値を突っ込んで、達成できるかどうかを見る」などというその場しのぎの実装はしないようにしましょう。



0.5の長さに出来てしまう入力の場合、「丸太の長さを0にしようとして、割り算で無限大を出しWA」になります。







しないようにしようね!(3敗)




F - Range Set Query




F - Range Set Query

問題概要


N個の玉が並んでいて、左からi番目の色はciです。

Q個の範囲について、その中の色の種類数を教えて下さい。



\\(N \\leq 5 \\times 10^5\\)

\\(ci \\leq N \\)




考えたこと


(WAどころか提出すらできていないので、迷走をお楽しみください)



・Queryの問題はSegmentation Treeなんですよ(自信満々)



・セグ木は関数をモノイドにしないといけないので、種類個の大きさのboolの配列を用意して、関数を各要素のORにすればいい。



→結果、bool[50万]を描く要素として持つ配列[524288]を宣言し、手元の環境でもMLEしました。







答えを読むと、「フェンウィックツリー」(New word)というのを使えばいいそうです。これは要復習ですね。

スポンサードリンク