Category: 日記

【Atcoder日記】ABC #365,367のC問題【二分探索、辞書順】

こんにちは。RockinWoolです。久しぶりの投稿になりました。メンタルを病んでパソコンに向かえない日々が続いておりましたが、なんとか乗り切ることができました。そして先日ついに茶色コーダーになることができました。さて、今回もAtcoderの挑戦日記になります。 二分探索法の問題 #365のC問題は色々計算して閾値を求めるよりも、二分探索で無骨に求める方が速さ的にも良いという(クソ)問題でした。解けなかったのは素直に悔しい。こういう閾値を求める系の問題が出てきたら二分探索法を疑うようにしなければ。二分探索法をコードは以下に示します。 これでmidに改良の余地がある限りはmidが調整されていき、最終的に一意に求まるという関数ができます。この考え方はよーく覚えておきたい。 低い方から辞書順に並べる問題 Atcoder367のC問題は初見では解くことができませんでした。そもそも解き方を知らないと対策できない系の問題でしたね。肝心となるのは「辞書順に低い方から並べる」という部分です。こういう数列の問題が出てきたら再起関数の実装問題なんだという合図のようです。 この関数の形は基本的に使いまわししたほうが良さそうなので、今後も同様の問題が出てきたら使えるようにしておきたいですね。 まとめ 二分探索法と辞書順に並べる問題の解き方について復習しました。目指せ緑コーダー!

【医療系雑学】フケ症の改善方法

こんにちはRockinWoolです。最近は筋トレにハマっていて自分の腕が太くなるのが毎日の楽しみになっています。現在休職中で時間があるわけなのですが、そんな中長年悩んでいたフケ症を改善しようと思いたち行動してみたら一気に良くなったので記事にしてみました。同じような悩みを抱えたエンジニアの皆様にも共有し改善できたら嬉しいです。それでは始めていきましょう。 フケ症を治すのに必要だったこと さて、私のフケ症は小学校5年からずーっと長い間改善できず、毎日丁寧に頭を洗ったりすることで隠し隠し生活してきていました。この度フケ症を治せた理由、それはズバリ病院にいったことです。 え、それだけ?って思うかもしれませんが、病院に行って病名と対処法を聞き、薬を飲みながら指示通りに生活するだけで治りました。正直数十年来の悩みがこんな簡単に治るとは思っていなかったので軽くショックを受けました。 病院からのアドバイス 病院の先生から言われたことはとても単純で、「頭をかくな」だけです。風呂でシャンプーするときも優しく撫でるだけ、むしろ泡が頭皮に触れていれば指は触れてはいけないレベルで大切にする。普段も絶対に刺激を与えてはいけない。100均で売っている頭皮ケアのトゲトゲも当然使ってはいけない。こんな感じでした。 実践・努力したこと さて、病院からの指示を守るために、まず意識のあるときは頭をかかないようにしました。結構かゆいときもありますが、そういうときはYANAGIYAで我慢したりしてともかく耐える。寝ているときに無意識にかきかけたときもありましたが、そういうときも自制しました。 結果 薬の効果もあったのか、2日後には頭皮の荒れはすべて収まり、1週間も経つ頃には筋トレしても白い粉が落ちないようになりました。人生初の出来事すぎてビビリました。というか、こんな単純なことを守るだけで治るのか・・・。 考察 エンジニアの方には多いと思うのですが、コードを書いているときなどに悩むと頭や顔をかいてしまうことがありますよね。私は結構無意識でこういうことをしがちだったので、顔や頭皮が荒れやすかったのだなあと感じました。爪を切るだけでも刺激が減って荒れにくくなるので、意識的に回数を減らしながらも無意識でも対策できるようにすると良いかもです。 まとめ 数十年来の悩み、フケ症の改善方法は意外にも単純で頭をかかないことでした。それを病院に行って学びつつ、薬と合わせて実践すればあっという間に治ります。同じ悩みを抱えている方、まずは病院に行って相談してみましょう。それでは、また次回!

【Atcoder日記】ABC #336

こんにちはRockinWoolです。最近は結構頑張って活動できていると思います。頭痛も寒さに慣れたからか軽減できていますしね。さて、1週間前の話になりますがABC#336を解いてみたので、解説と比較していこうと思います。今回は45分で3問も解けたので自分を褒めたい一方で、4問目で完全にスタックしたので解法を確認していこうと思います。それでは。 A問題 龍文字列 なんのことは無い平凡なA問題です。oをN個付ければ良いだけなのでかんたんでした。 B問題 CTZ 2進数化した時に、末尾に何個0が連続するかを算出する問題です。一般的に使われるc++のライブラリではstring型で出てこないため0の個数を確認することができませんでした。そこで、自作でstring型の2進数を返すtoBinaryを作ってやれば解決します。 ちなみに公式ではbitsライブラリを使って下記のように解いていました。 まずint nがbitとして扱えることに驚き、次に1を左にi個シフトするのを1<<iと表現するのがびっくりですね。あとは、左にi桁シフトした1とnでandを取って0でなければ0がi個あることになるという仕組みです。1<<iの挙動に関しては下記プログラムで確認しました。 これだとn=3で8, n=2で4, n=1で2, n=0で1を出力します。左にn個シフトしていることがわかりますね。 C問題 EvenDigits 5個の数字{0,2,4,6,8}のみを使って低い順に並べて、i番目に低い数字を答えるという問題。これは{0,1,2,3,4}だったとしたら5進数を答えれば良いと気づけたので、B問題のtoBinaryを流用して5進数を算出する関数を作ればクリアです。 コードの質と量は全然違いますが、公式でもまったく同じ解き方をしていたので嬉しいですね。公式から学べることとしては、for(int i=Fifnary.size()-1;i>=0;i–)の部分をreverse(Fifnary.begin(),Fifnary.end())と書けたということでしょうか。 D問題 ピラミッド数列 ピラミッド数列を考えるときにまず困ったのは1,1,2,2,3,2,2,1のように、もともとの数列の中心を軸にピラミッドを作ると121が算出されるけれど、本当の最大ピラミッドは12321のパターンです。結局これが解けなかったのでこの問題でスタックしました。さて、公式の回答をここで見てみましょう。 解説を読んだのですが、かなり複雑で難しいです。解説を写経してなんとか意味はわかったのですが、これを時間内に解くとなるとなにかが必要ですね。 まとめ D問題に初めて挑戦してみましたが、かなり難しいですね。これからも精進していつかは解けるようになりたいものです。それではまた次回!

C++の備忘録: クラスを作ってファイルを分ける時に詰まったこと

こんにちはRockinWoolです。C++のプログラムが大きくなりそうだったので、クラスを作ってわかりやすく管理してやろう!と思ったわけですよ。しかし、なんか見知らぬエラーが連発してなんじゃこりゃってなったので、対策方法をメモして残しておきます。先に言っておきますが、かなり初心者レベルのことに今更気づいてドヤ顔しているので内容は結構恥ずかしいです。 おかしい。クラスを読み取ってくれない。 最近読んだリーダブルコードにもありました通り、本質的では無いコードはutilに突っ込んでメインは読みやすくしたい。そのためにはクラス化してpublicな関数とprivateな関数に分けてやろう!と意気込んだわけです。しかし、問題が。下記のようなプログラム構成にしたのですが、関数の定義が見つからないよというエラーが出てしまうのです。 「関数が定義されていない」というのであれば関数は定義されていないのでしょう。さて、何が問題だったのか? CMakeLists.txtにライブラリファイルの登録をする必要があった 上記のミスはCMakeLists.txtに設定を追記していなかったことにより発生しておりました。下記にChatGPTとの会話を載せておきます。簡単に言えばadd_executable以外にもadd_libraryとtarget_link_librariesの2つを設定する必要がありました。 したがって、CMakeLists.txtは次のように書き換える必要があります。 ヘッダファイルからのincludeは不要 さて、上記のエラーを解決するのにはかなりの時間を要しました。というのも、このCやC++の仕様が気持ち悪くて何回躓いても納得できない!過去の自分と同じエラーで引っかかったので悔しいを通り越して怒りになっているのですが、サンプルプログラムを作ったりしながら試行錯誤を続けているうちに気づくことができたのは偉かった。エラーの原因ですが、utils.hに#include util/myclass.cppを書いていたのが原因でした。utils.hを読んだ時にクラスの定義より先にmyclass.cppの中のMyclass::hoge()関数を読もうとして、「Myclassなんて無いんだけど?」ってなったのが先のエラーです。確かにあとから見ればそんなの当たり前に感じますよね。でも、これってCMakeLists.txtに追記した内容を理解していないと遭遇してしまうと思うんです。pythonを書き慣れている私からすると、親子関係にあるプログラムは親でimport宣言をして子の関数を呼び出せるようにするのが当たり前。ということはutils.hで宣言する関数も実際に書かれているmyclass.cppからimportしなければならないのでは?と考えてしまうのです。(今でもその感覚は抜けていない)なので、ヘッダファイルで行っているのはあくまで関数のプロトタイプ宣言であり、utils.hとmyclass.cppでライブラリを作ったあと、utils.hとmain.cppでメインを作って、それらをリンクさせるという一連のCMakeLists.txtの動作を理解しないと、この違和感は払拭できないわけです。 まとめ 結局このエラーを解消するのに半日使ってしまったので、今となっては完全にやる気が削がれてしまいました。しかし、この経験をバネに日記を書いて次回につなげて行こうと思います。それではここまで長々とお付き合いいただきありがとうございました。

C++の備忘録#2: 配列の中身チェッカー、CSV入出力のあれこれ

こんにちは。寒くなるにつれて頭痛の酷さが増してきている気がするRockinWoolです。運動不足が影響しているのではないかと思って今日は外を歩いてみたり、2年ぶりくらいにカラオケをしてみたり、風呂に長めに入ってみたりしたけれど効果はありませんでした。仕方無いのでC++の備忘録の第二弾をやって少しでも成長を感じていこうと思います。 配列の中身チェッカ 関数のオーバーロードの練習を兼ねて作ったプログラムです。もし引数がvector<int>だったら、その中身を1行で出力します。vector<vector<int>>だったら全要素を順番に表示します。まずは引数がvector<int>だった場合。 解説するほどの場所は無いかもしれませんが、vec.size()で配列の長さを取得しているところが工夫ですかね。次はvector<vector<int>>の場合。 同じvector_checker()という名前ですが、引数が2次元だとこちらが呼ばれます。工夫はvec.size()-1の範囲でコロンを打つようにしている部分ですかね。これらのプログラムは挙動が想像しやすいように書けたと思うのでGood jobだと思います。 失敗事例: vectorでは無い場合 次はバグを生んだプログラムの紹介です。下記のプログラムのバグを見つけてみましょう。 このプログラムを回した際の出力は1,2,3,4,5,0,937289472,-494252404,になります。何か知らない数が生まれてきていますね。ちなみにこれをChatGPTに相談してみたところの回答が下記になります。 The issue you’re encountering is related to how arrays are passed as pointers in C++. When you pass an array…

【日記】スパゲティコードの治療#002【断念】

こんにちは。RockinWoolです。寒くなるにつれ頭痛もひどくなってきている気がしますが、皆さんも暖房をケチらずに温かい部屋で過ごしましょう。さて、今回のお題はとあるスパゲティコードの治療を諦めた話をしようと思います。このプログラムの何がいけなかったのか。自己分析をしながら話していこうと思います。 治療断念の決断: 存在意義が無い 皆さんの中でも、自分の書いたプログラムに対し「破棄をする」という決断をすることは珍しいと思います。どんなコードでも一度書いたものは大切に使いまわしたいし、複雑なコードであればあるほど時間をかけてつくった愛着から捨てられなくなりがちです。ですが、今回の私のプログラムは救いようがありませんでした。なぜなら、作者本人からしてみても、そのプログラムを回して何をしたかったのかがわからなかったからです。 スパゲティコードは維持するだけで負債になりうる さて、半年前に書いたと思われるこのコード。内容を確認してみようとすると大きな問題にぶつかります。そもそも、かなり読みにくいのです。これを頑張って解読したのですが、結局何がしたかったのかは半分くらいしかわかりませんでした。しかも、ここで動作チェック中にバグを発見してしまいました。このバグを治すかどうかを時間と天秤にかけて、このコードをメンテしつづけるくらいならば破棄した方が人生にプラスであると考えました。つまり、治しても価値の無いものを治すくらいであれば、破棄した方が良いのです。 どうすれば回避できた? 今回の問題はコードの構成も去ることながら、コードを使って何を実現したかったのかという「目的」の部分が欠落していた点が一番大きな要因として挙げられます。単純な動作確認プログラムの延長であったことはわかるのですが、何の動作を確認してどうしたかったのかが残って無い以上、推測の範囲でしか当時の自分の気持ちを読み解くことができないのです。したがって、このような事態を防ぐためには「必要なもの」を「ドキュメントを残しながら」作っていくことが必要です。どんなプログラムも書いている時は、自分にとって必要なプログラムであるはず。この存在意義を残していないと、あとになって大切であるかもしれないそのプログラムを捨てるしかなくなってしまう。今回はそれを学ぶことができました。 動くものを作って、いつでも使えるようにする 使いきりのプログラムを作ると、必ず半年後にはその存在意義や実装の詳細を忘れてしまうでしょう。使い切りにせず、常に使えるようにドキュメントを作ったり、動作方法を簡単にする、GUIを作るなど、工夫しようとおもいました。それと、そもそも動かないプログラムは破棄しましょう。今回動かないプログラムを治療しようと思いましたが、当時の知識を失っている以上どうしようもなかったです。せめて動くプログラムを管理しましょう。 まとめ: 定期的なプログラムの破棄は大切である 締めになりますが、今回のプログラムを破棄するという判断は間違っていないと信じたいです。そもそも一生プログラムを書き続けたら、そのうちGitHubはゴミコードでいっぱいになってしまいます。定期的に破棄し続ける心構えを持てればいいなと思います。それでは、また次回。