年末年始に読む本を決めかねている

読書は好きでしょうか。ぼくは好きです。 紙の本も電子書籍も好きで、手でページをめくるのがそもそも好きです。

めちゃくちゃ本読むけど読書嫌い、という方はあまりいないでしょう。たぶん読めば読むほど自分なりの楽しみ方が分かってきます。

積ん読があるのにまた新しい本を買ってしまいます。読み終わってない、読んでないけど手元に積んである本のことです。今日はどれをポケットに入れ、家に帰ってきてからはどれを読もうかと悩む無駄な時間も好きだからです。

今年は何冊読んだか分かりませんが今までで一番多かったです。読書の何がいいのか少し書いて、今まで読んだ本からよかったやつを簡単にまとめます。よければどうぞ。

MoriHiroshiBooks

読書の何がいいのか

脳に擬似体験をさせてみる

どんな本を読んでいる時でも、その内容を全身で感じるシミュレーションが頭の中で起動しています。

漫画・小説・歴史書・特定分野の専門書などそれぞれの本が、扱う場所・時代・登場人物や著者の生い立ちや性格といった基盤となる前提条件を持ちます。読んだ瞬間から半強制的に脳はそれら条件の中で生きる擬似体験を始め、まるで自分自身が書かれた知識を持ち、書かれたように行動し、書かれたように物事を感じるかのようにトレースしていきます。この「他人トレース」によって、自分の思考回路の繋がりが組み替わったり知らなかった知識の世界地図が頭の中に追加されたりします。

というようにものの見方や性格や人生設計までを変えてくれる可能性を秘めながら、それを手に持って自分のペースで味わっていけるのが楽しみのひとつです。

知識を拡張する

個人的には最近プログラミングや研究の専門書を買う方が多いです。全ての本に共通して(専門書は特に)、内容を全て覚えて手元に置いておくのではありません。この本にはこういう話が入っていて、こういう感情や知識を手にできる、という索引を頭の中に増やしていきます。これを勝手に「知識を拡張する」と呼んでいます。

最近「生きていくうえでは何かを参照して問題を解決できる能力こそ使うし、カンニング許してよくない?」みたいなツイートをしました。いまの人類はいろんな機械や先人の知恵の上に生きているので、こだわり抜きたいところ以外では先人の知恵である本を上手く使いこなし自分にとっての良い思いをしやすくしていくのが大事だと思っています。

オススメ本

Amazonのリンクを貼っていますが、そのままポチって頂いてもぼくにアフィリエイトは1円も入りません。買ってみたよって言っていただければ紹介して良かったなってなります。説明しすぎるとそのバイアスを持って読み始めてしまうので、最小限に留めます。

個人的には、本を買うのはメルカリでも古本屋でも書店でも通販でも何でも良いと思っています。著者さんにお金が入って欲しいのは勿論なんですが、ぼくひとりがどう買おうがほぼ何も変わりません。時には自分ひとりのスケールで損得勘定をするのも大事だと思っています。これから頑張って生きて、お金が自身の人的資本を増やさなくなってきたと感じたら書店で新品を買います。もし名前が少しは世に知られるようになったら、直接に近いかたちで感謝を伝えたいです。

本紹介までが長い。

すべてがFになる (講談社文庫)

すべてがFになる (講談社文庫)

  • 作者:森 博嗣
  • 発売日: 1998/12/11
  • メディア: 文庫

小説はこのミステリシリーズ以外滅多に読みません。著者の森博嗣さんも登場人物も人間性がハッキリと分かる天才で、読んだ後に回収された伏線と次回以降に続く新たな伏線にいつも1冊読んでは余韻が長く残ります。死ぬ間際の自分が今の自分のために買いてくれたのだろうかと思うほどど真ん中で好きです。今46作目ぐらいまで読み進めました。

小説は探せば自分の好みを満たすものが必ずあります。逆に「こんな思考回路の人間もいるのか」と体験して今後の人間関係を幾分か生きやすくする使い方もあります。思考回路を知りたい人にオススメを聞いたり古本屋で手当たり次第買ってみたりして、自分にとっての味方を見つけてください。

人間がいかにコミュニケーションを複雑に理解し運用しているか。 とても読みやすく面白いファンタジー小説を通して、昨今のAIが学習を行う方法と研究者の苦悩が垣間見られます。

思い通りに運んでない時はもう少し判断材料を多く、質を高くすればいいのかと心底納得しました。 優しく明快に「正しく理解して初めて問題は解決に向かう」と理解させてくれます。

知的創造のヒント (ちくま学芸文庫)

知的創造のヒント (ちくま学芸文庫)

頭を上手く使うヒントだらけです。知識を醸造する話が一番好きです。 外山滋比古さんの本は1冊しっかり読むのが一番ちょうど良い。

人生は、運よりも実力よりも「勘違いさせる力」で決まっている

人生は、運よりも実力よりも「勘違いさせる力」で決まっている

  • 作者:ふろむだ
  • 発売日: 2018/08/09
  • メディア: 単行本(ソフトカバー)

環境は人の性格や人生設計を簡単に変えてきます。属するコミュニティと接する人たちが今の自分を表します。良い環境が良いループをぶん回します。望む生き方と現状が乖離していれば脱出の機運です。収まるところに収まるのもまた自分、人間にも人生にも良い悪いの評価軸は無いので、自身の気持ちと相談するきっかけに。

天才はあきらめた (朝日文庫)

天才はあきらめた (朝日文庫)

  • 作者:山里亮太
  • 発売日: 2018/07/06
  • メディア: 文庫

売れている芸人さんは自他両方について分析の解像度がかなり高いです。 山里さんのモチベーション維持についての考え方は、普段モチベとかやる気とか考えない人ほど参考になりそうです。 私ごとですが今年友達2人にM-1に誘っていただき出場した際には、1回戦敗退ながら笑いについて深い洞察を幾つも得ました。少しでも関わってみた世界はもう他人事とは思えません。お笑い芸人は芸術家やミュージシャンやアイドルのように個人が個人を直接好きになる要素が強い稀有な職業だと思います。そして塙さんはいつでも誰よりもお笑いを考えているようです。 来年は2回戦いきたい。

とにかく心優しく、関わる人みんなをポジティブに仕事へと駆り立てる元任天堂社長・岩田聡さんの人間性が詰まっています。 相手に変化を望む時には一貫して自らの真摯さを見せ、内側から突き動かす姿勢はどこを何度読んでも刺さります。

次は7冊まとめて。

臆病者のための億万長者入門 (文春新書)

臆病者のための億万長者入門 (文春新書)

  • 作者:橘 玲
  • 発売日: 2014/05/20
  • メディア: 新書

元財務官僚が5つの失敗をしてたどり着いた これからの投資の思考法

元財務官僚が5つの失敗をしてたどり着いた これからの投資の思考法

  • 作者:柴山 和久
  • 発売日: 2018/11/15
  • メディア: 単行本(ソフトカバー)

本は好きな人が読むものですが、「お金まわりの知識」と「自身の思考回路は過去に存在したか」だけは何かで知るとさすがに少しは良いんじゃないかなと思います。生きている限り働いて悩んで幸せになっていくその道中にずっと付き纏う話なので、知ってさえいれば悩まずに間違えずに済む分岐選択では上手く進みたいです。

上4冊がお金を考える入り口、この下の3冊が哲学・心理学など思考体系の入り口的な本です。『ウォール街のランダム・ウォーカー』だけ500ページぐらいインデックス中心に株式投資の話してるデカ本でかなり時間掛かるので、チャレンジする方は頑張って...。

嫌われる勇気―――自己啓発の源流「アドラー」の教え

嫌われる勇気―――自己啓発の源流「アドラー」の教え

幸せになる勇気――自己啓発の源流「アドラー」の教えII

幸せになる勇気――自己啓発の源流「アドラー」の教えII

『嫌われる勇気』と『幸せになる勇気』はアドラー心理学の入門的ビジネス書です。ここではアドラー心理学を理解してほしいのではなく、自分なりに固まってきてる考え方にはより傑作がおそらく過去にあったことを伝えたい。責任範囲を自他で分離し、自分の愛から始め、刹那を生きるというアドラー心理学の遠大な枠組みが、ここ数年で気付きつつまとまりつつあった自分の思想とキレイに重なり感動しました。そうなれば自身の考え以外の部分は、これまで気付いていなかったヒントとなる考え方の可能性がかなり高いです。

『武器になる哲学』も哲学の小難しい話は無くひたすら実用主義的に「こんな考え方したことありません?実は◯◯って哲学者は...」と淡々とまとめており、もやもやとした考えの断片を引っ張り出してキレイな武器にしてくれるかもしれません。 偉大な超賢い先人たちが死ぬほど考えて、だいたいの人間の悩みや考え方について一般的な答えを出しています。挙げた7冊は入り口の1つに過ぎないので、バイブルが見つかりますように。

鬼滅の刃 1 (ジャンプコミックス)

鬼滅の刃 1 (ジャンプコミックス)

マジで良い漫画です。笑いどころがけっこう面白いし、敵味方問わず生い立ちが形成した思想に毎回泣いてしまうし、セリフが刺さるし響くし、18巻オトナ買いして本当に良かった。 読んでる方いたらまた話しましょう。

まだ途中でもオススメの本

ここからは今途中まで読んでて良い感じに面白いやつを無責任に列挙します。むずくてゴツいので時間かかってるやつばっかりです。

音楽の哲学入門

音楽の哲学入門

プログラミングする人向け良かった本

UIデザインの教科書[新版] マルチデバイス時代のインターフェース設計

UIデザインの教科書[新版] マルチデバイス時代のインターフェース設計

  • 作者:原田 秀司
  • 発売日: 2019/01/21
  • メディア: 単行本(ソフトカバー)

マイクロインタラクション ―UI/UXデザインの神が宿る細部

マイクロインタラクション ―UI/UXデザインの神が宿る細部

  • 作者:Dan Saffer
  • 発売日: 2014/03/19
  • メディア: 単行本(ソフトカバー)

UNIXという考え方―その設計思想と哲学

UNIXという考え方―その設計思想と哲学

  • 作者:Mike Gancarz
  • 発売日: 2001/02/01
  • メディア: 単行本

Effective C++ 第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTI)

Effective C++ 第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTI)

実践TypeScript ~	BFFとNext.js&Nuxt.jsの型定義~

実践TypeScript ~ BFFとNext.js&Nuxt.jsの型定義~

  • 作者:吉井 健文
  • 発売日: 2019/06/26
  • メディア: 単行本(ソフトカバー)

改訂2版 みんなのGo言語

改訂2版 みんなのGo言語

おわりに

お付き合い頂きありがとうございました。他にもオススメ聞いていただければ知りうる範囲で答えてみます。

自分の堂々と欲しい本リストを貼って終える。

https://www.amazon.jp/hz/wishlist/ls/35NLEG21HHTG3?ref_=wl_share

名前がついているとラクだけど危険

Twitter見てたらこんなのが(正確にはこれを批判したツイートが)流れてきました。

どう交際しているかは2人の自由なので議論の意味はまるで無いのですが、画像1枚目の最初の「〜〜〜な行為は浮気です」に(あくまで個人的に)めちゃくちゃ違和感を感じました。
この方がどうとかいう気持ちではなく、最近考えた一般論を思い出したのでなんとなくブログを書いてみます。
あと最近競技プログラミング以外の記事を書きたいと思っていたところで丁度よかった。

あくまで自分の考えである部分はほとんど「だと思います」みたいな文末にしており、たかが一個人の考え方です。
あと、まとめる作業をしないまま思いついた順に書いたので筋道がバラバラで言いたいことが散らばってしまいました。時間あれば直します。



名前をつける、ということ

固有名詞は置いといて、名前っていろんなものとか現象についてますよね。
ノートパソコン、黒板、車、タピオカ、人間、などこの世に実体として存在していたり、恐怖、四角、甘み、危険、など感覚的だったりします。
厳密な区分があるのかは知りませんが、そういう厳密な議論をする記事ではないのでなんとなく「まぁそうかもな」ぐらいで進んでください。

それぞれのものの名前は、辞書やみんなの共通認識によって指し示す対象が決まって使われています。
そしてある程度は文化圏や世代によらず、知らなくても説明されればその名前が指すものがだいたいわかるようになると思います。
外国語にもだいたい一対一対応で同じものを指す単語が存在しますよね。(この本を思い出した 面白くてめちゃめちゃ読み進めやすいので誰にでもオススメです)

「名前がつく」ということは、よく見るものを他の言葉でいちいち長く説明する手間を省く、ということだと思います。
「キャッサバという大根みたいな芋から作ったでんぷん粉と水と練って熱したあと粒状に乾燥させたもの」っていちいち言うより「タピオカ」という名前をつけた方が今後「タピオカが指すもの」が出てくる話がしやすくなるわけです。

f:id:Sandglass:20190621161507j:plain
キャッサバ

モノならこれでただ便利になってはっぴーです。ラクですね。
しかしさっき言った概念的な言葉は定義や辞書の意味を意識することは稀であり、個人が今まで形作ってきた感覚に基づいて使うことが多いと思います。

例えば「怖いってどういうことを指してる?」と聞かれたら説明するのに苦労しますが、みんな多分「怖い」のイメージは似ていると思います。
思い浮かべるもの(怖い対象)が雷、虫、ジェットコースター、おばけ、犯罪、夜道など人によって違うためイメージに個人差がありそうですが、指し示したい心の状態は同じっぽい気がするのでみんな「怖い」という単語が会話や文章で使えますよね。

ただちょっと厄介で議論になりやすいのが「そういう意味は無いのにイメージがひっついている言葉」です。

イメージが意味になり始めると危険

このような言葉の何が厄介かと言うと、「その言葉に結びつくイメージまで誘発されること」だと思います。
ここからしばらく冒頭のツイートで出てきた「浮気」という単語を例にします。

たとえば多くの人は「浮気」に「してはいけないこと」「する人間は信用ならない」みたいなネガティブなイメージがひっついていると思いますが、「浮気」という単語そのものには「ダメなこと」みたいな意味は全く含まれていません。
浮気という言葉は「夫婦または交際関係にあるにも関わらず別の異性に気持ちが移ること」であり、それに伴う「お互いに好きで大切に思っている、という信頼を裏切り相手を悲しませる」という行為に対する「個人個人の考え」が連想されるためにそんなイメージを抱いています。

そしてその「お互いに好きで大切に思っている、という信頼を裏切り相手を悲しませる行為」がダメであるという本質を考えずに「浮気」というのはダメな行為である、と短絡して決め込んでしまっていることがめちゃくちゃ危険です。
手段と目的が入れ替わっている、というやつに似ています。

会議に時間通り出席して発言したり話を聞いたりするのは「プロジェクトや目標の達成のために関係者が情報や現状を共有し議論することで達成へと近付くため」だから出席態度チェックがあるのに、いつしか「そのチェックが達成しないといけないタスク」みたいに捉え始めてみんな出席と態度に気を遣うようになっちゃった結果情報共有とか目標の確認が出来てない人がいる、みたいなことです。

つまり「浮気」の問題点はどんなことをしたかではなく「相手が他の異性に気が移ったことで傷ついたか」こそが本質であり核心なのに、その行為の内容が「浮気」という言葉の指す行為に当てはまるかどうかばかりを気にしてしまい「当てはまるから良くない、最低だ(紐づいた悪い印象を受けてしまっている)」みたいな見当違いの道を歩んでしまいます。
また芸能人が浮気を報じられたニュースやバズったツイートを見た全く関係の無い人たちも、同じような認識で的外れで価値の無い議論が燃えているのをよく見ます。

そしてそれは当の本人たちの問題なので、結局自分のことじゃない話には口を挟む余地も意味も無い、ってことですね。
なんか違う話な気もしますが。

目的は何だったっけ

同じことが当てはめられるなーと思う例をもうひとつ、「○○ハラスメント」です。
最近よく耳にしますね。
もううるさいかと思いますが、ハラスメントは何かしらの言動が相手に嫌な思いをさせることを指す単語で、問題となる場合の本質、確信はその「嫌な思い」です。

「彼氏できた?」という質問を大学時代の友達にされたら、もちろんある程度心理的距離が近いうえにそういう話になることも多々あるので大抵は「世間話」になりますが、仕事上の関係でしかない職場の上司に聞かれると「友好関係があるわけではない人から個人的なことを聞かれて嫌だ」と思われ下心の有無に関わらずセクハラになるかもしれません。

ハラスメントがその意味を定義されるべき対象は「嫌な思いをしているかどうか、またそれはどの程度か」であり、内容や行為そのもので計ることはできません。
特定の言葉や行為に「○○ハラスメント」という名前がついている、と(無意識にでも)思っている人は「それ○○ハラじゃない?」みたいな問題の本質とズレた確認だけをして終わってしまいます。
重要なのは「行為がハラスメントという言葉のイメージに当てはまるか」ではなく「嫌な思いをしているかどうか」だということです。

目的つながりで言うとドラマ『わたし定時で帰ります』とかちょっと前から始まった「働き方改革」がめちゃくちゃ賛否両論ありました。
「定時で帰ること」が問題かどうかというマジで意味の無い議論が生まれていましたが、定時帰りは自分のプライベートを確保したい人のための手段であり目的に据えるべきものではありません。

言葉は「先にものや考えが存在していたところに後から意思疎通をスムーズにするために付与されるもの」であり、ざっくり言えば手段です。
ある言葉を使う目的は「自分を含む複数の人たちの間に共通の認識を素早く呼び起こすこと」なので、使われた言葉たちそのものより話の本質とゴールを忘れずに考えるのが大事です。
ちょっと気を抜くとすぐ忘れがちになりますけどね。

逆に言えば、使われた言葉の端々には深層心理とか本音が現れているということもできます。
誰かの言葉に違和感を持ったり腹が立ったりしても、よく噛み砕いたり他の人に伝えてみたりすると違う視点からの気づきがあるかもしれません。

そして自分の言葉遣いも「出来るだけ正確に考えていることが伝わるようにもう一段考えてみる」ことができます。
例えばこのアカウント。
twitter.com
英語を覚えるだけではなく「普段使いする言葉ってもう一段階細かく言い分けることが出来るんだな」と気付きます。
スッと出てくるような普段使いする言葉は指し示す範囲がデカいことが多いので、より正確に自分の言いたいことを表す言葉をもう一段深く探す習慣をつけると誤解を避けることができそうかなと心がけています。

まとめ

  • 「どこからが浮気か?」とか「最近はすぐハラスメントだと言う」みたいな話は「その単語のイメージに当てはまるかどうか」を決めるのが目的になってしまっている
  • 名前がついていると便利ですぐ使ってしまうけど、それが指すものは何だったっけと考える
  • 知らんとこで起こってることに勝手に腹を立てない(完全についで)

雑記

なんで俺はこんな記事を書こうと思い立ったのか思い出せない。
これからスキを見つけていろんなもの書いてみたいなーと思います、リクエストあったらください。
最後まで読んでいただきありがとうございました。

AtCoder Beginner Contest 130 A~DをPythonで解く

このブログ、ほぼAtCoderの振り返りしか書いてない

atcoder.jp

相変わらずのA~C3完だったのですが、今日は簡単な回だった気がします



A - Rounding

正の整数Xを0か10に丸め込む閾値をAに設定する、という問題
のんびり慎重派なので、どれだけ簡単そうな問題でも文中の入力例は全て試します

x, a = map(int, input().split())

print(0 if x < a else 10)

B - Bounding

0から順に入力値を足していった時にXより大きくなるのはいつか、という問題
最後までXを超えないケースが漏れるコード設計をしてしまい一度WAをくらいました
慎重派じゃなかったのかよ...

n, x = map(int, input().split())
distances = list(map(int, input().split()))

d = 0
cnt = 1
for l in distances:
  d += l
  if d <= x:
    cnt += 1
  else:
    break

print(cnt)

C - Rectangle Cutting

長方形の内部または辺上のある一点を通って二分するとき、小さい方の最大値を求める
またその最大値となる切り方がただ一つか複数あるかを求める問題

AtCoderで初めてこんなにしっかりした算数、数学の香りがする問題に出くわした気がして狼狽えました
10分ぐらいあれこれ切り方を考えてるときに
あれ...中心通る線ならいつでも半分にできるくない...?
と脳内のギャルが閃きました
もっと早く分かりたかったという謎の傷を心に負ったまま「最大値になる(ある一点と中心を通る)切り方が複数パターンあるのは、ある一点が中心そのものである時だけ」という条件を加えて無事AC

w, h, x, y = map(int, input().split())

area = w * h
if x * 2 == w and y * 2 == h:
  center = 1
else:
  center = 0
  
print('{} {}'.format(area/2, center))

いつものCより解ける人多いから今日のパフォ下がりそうだなという生温かい気持ち

D - Enough Array

自然数列Aの連続する部分列のうち、その和がKを超えるものはいくつあるかという問題
解き方まで含めて典型問題としてどこかにありそうな気がしませんか?
N^2の愚直実装(以下)をそっと出して撤退したんですけどね

n, k = map(int, input().split())
numbers = list(map(int, input().split()))

cnt = 0
for i in range(n):
  for j in range(i, n):
    if k <= sum(numbers[i:j+1]):
      cnt += 1
      
print(cnt)

このやり方に無駄が多いのは明らかで、ポイントとしては

  • ある部分和がK以上なら、それが含まれている部分列は全て和がK以上
  • 連続する部分列を考えるので、最初に左端の要素1つだけの部分列から始まって左右の仕切りが右端に辿り着けば求め終わっている

みたいなところがあるんじゃないかなと思いました

しゃくとり法というんですね
言われてみれば確かにそういう名前をしています(無知)
「競プロの勉強時間」もインターンひと段落したら取っていきたい
その頃には低めにレート出るやつもなくなって頭打ちになってると思うので頑張れそうです

解説だけ読んでPythonでACすることができました

n, k = map(int, input().split())
numbers = list(map(int, input().split()))

cnt = 0
right = 0
s = 0
for i in range(n):
  while s < k:
    if right == n:
      break
    else:
      s += numbers[right]
      right += 1
  if s < k:
    break
  cnt += n - right + 1
  s -= numbers[i]
  
print(cnt)

「持っとける値は全部持っといた方がいいことある」という学び

雑記

大学時代に知り合った人が最近とんでもない勢いで結婚を始めています
数えてみたら学部、軽音、働いていたバーで計25組35人くらいの知り合いが結婚しました
さらに結婚しそうな人たちを同じくらい知っています

並みのメンタルでは結構焦ると思いますが、現段階での

  • やりたい仕事
  • やりたい勉強
  • 人生設計

をなかなかしっかり決めて持ってると思っているのでただただおめでとうみんなという気持ちです

本気で人類みんな幸せになってくれと思っているので
知っている人たちが幸せになるのは特にめちゃくちゃ嬉しいことです

俺に関わったことで関わってくれた人たちの人生がいつかどこかで何かしら少しでも良くなったら、という気持ちが行動原理のかなりの部分を占めているので
何か気づきや幸せを与えれる人になっていきたいですね

今日は雑記多かった
ブログっぽい(?)

AtCoder Beginner Contest 129 A~DをPythonで解く

週末といえばABCですね

atcoder.jp

A、B、Cの3完でした
茶色になってからもレート上がったので一安心です

A - Airplane

3つの自然数のうち2つ選んだ時の和が最小となるのはどれか、という問題

この曲がめちゃくちゃ脳内再生されました
www.youtube.com
BTSのメンバーが出したソロ曲です
BTS、曲とダンス死ぬほどカッコいいのでチェックしてみてください
www.youtube.com
何を歌ってるのかは僕もまだ全然分かりません

3数から2数選んだ和は3通りありますが、3つ求めて最小取る実装をわざわざ書くのアレだなと思っていたら
3つの和から最大のヤツ引けばいい
と閃きました
めんどくさがることが良いプログラムを書くための足掛かりのひとつなのかもしれません、知らんけど

a, b, c = map(int, input().split())

print(a + b + c - max(a, b, c))

B - Balance

N個の自然数を前後2つに分けてそれぞれの総和を求めるとき、その差が最小となる切れ目はどこかという問題

Nがデカい時は違うやり方考えるんだろうなと思いながら愚直実装です
A、Bで「C問題以降でも計算量的にちゃんと大丈夫な解法」をスッと思いつく脳にしていきたいですね
制約が緩いことにかまけて愚直実装でササっと終えがちです、そんなに急いでやってるわけでもないのに...

n = int(input())
weights = list(map(int, input().split()))

diff = sum(weights)
for i in range(n):
  if abs(sum(weights[:i]) - sum(weights[i:])) < diff:
    diff = abs(sum(weights[:i]) - sum(weights[i:]))
    
print(diff)

C - Typical Stairs

初見で「うわ今日のC問題動的計画法みたいな設定や...知らんけど...概要だけ知ってて実装したこと無い...」と狼狽えましたが
試しに紙に書いて考えてみたところ

  • ある段にたどり着くには、一段下から来るのと二段下から来るのしか無い
  • 三項間漸化式っぽいなー懐かしー
  • 壊れた階段では「そこまで来る方法の総数がそのまま二段上にコピー(?)される」とみなす
  • 「壊れた階段をスキップしたばかり」「そこから一段上った」「一段下と二段下の両方から来ることができる」の3状態しかない

などに気付いて実装してみました
もしかしてこれが動的計画法..?(知らんけど)

ムダが多い(inが冗長すぎ)と心配しながら提出したらTLEをくらったのがこちら

n, m = map(int, input().split())
broken = [int(input()) for _ in range(m)]

ways = [0] * (n+1)
ways[0] = 1
keep = 1
noway = False
for i in range(1, n+1):
  if i in broken:
    if i-1 in broken:
      noway = True
      break
    ways[i] = ways[i-1]
    keep = 0
  else:
    if keep == 2:
      ways[i] = ways[i-1] + ways[i-2]
    else:
      ways[i] = ways[i-1]
      keep += 1
      
print(ways[-1] % 1000000007 if not noway else 0)
  • 3状態を遷移したい
  • 全ての段でひとつ操作をして次へ、としたい
  • 壊れている段は保持しておく
  • 2段連続で壊れてたら0を表示するようにしとかないと

などの欲望を頭の中ごちゃごちゃのまま実装したら案の定TLEでした
inで調べる操作どう考えてもやりすぎてる

無事AC通ったのがこちら

n, m = map(int, input().split())
broken = [int(input()) for _ in range(m)]

ways = [1] * (n+1)
for i in broken:
  ways[i] = 0
  
keep = 1
for i in range(1, n+1):
  if ways[i]:
    if keep == 2:
      ways[i] = ways[i-1] + ways[i-2]
    elif keep == 1:
      ways[i] = ways[i-1]
      keep += 1
    else:
      ways[i] = ways[i-2]
      keep += 1
  else:
    keep = 0
      
print(ways[-1] % 1000000007)

シンプルになって動作時間も短いという素敵な結果です
プログラミングって世の中では数少ない「完全上位互換」が存在する世界ですよね
だいたいのものって何かしらのトレードオフ関係があるのでそこがプログラミング好きポイントのひとつです

D - Lamp

DSソフトのレイトン教授に似たような問題があったなぁと懐かしみながら22時過ぎから用事があったため見送りました

レイトン教授では全マスを照らすのに必要なランプの最小個数を求める問題でした
マジで良いゲームだったな...

解説を読んでAC通せたので掲載します

学びとして

  • 「事前に計算しておくといいモノがある」というケースが存在する
  • 2000×2000のマスはいくつ作ろうが計算量は10^{6}オーダーであり、作業が階層にならなければ大丈夫

がありました

計算量制約への苦手意識がまだ全然取れていないので、2つ目が自然な発想にまだ組み込まれていませんでした
本番でも解けなかったと思います
方針としては「そのマスから上下左右それぞれについてどれだけ照らせるかマップを作成する」のが肝ですね

h, w = map(int, input().split())
s = [input() for _ in range(h)]

l = [[0] * w for _ in range(h)]
r = [[0] * w for _ in range(h)]
u = [[0] * w for _ in range(h)]
d = [[0] * w for _ in range(h)]

for i in range(h):
  for j in range(w):
    if s[i][j] == '.':
      l[i][j] = l[i][j-1] + 1
      u[i][j] = u[i-1][j] + 1
    if s[i][-j-1] == '.':
      r[i][-j-1] = r[i][-j] + 1
    if s[-i-1][j] == '.':
      d[-i-1][j] = d[-i][j] + 1
    
torch = 0
for i in range(h):
  for j in range(w):
    torch = max(torch, l[i][j]+r[i][j]+u[i][j]+d[i][j]-3)

print(torch)

AtCoderを始めて考えをプログラムに起こす力が確実に上がりました
マジでやってよかったと既に思えるのではっぴーです

雑記

目標を「安定してCを解けるようになりたい」というより「Dをたまに解ける」に設定した方がいいかなと思いました
今回から解けた問題の次を実装してみるという勉強法を始めてみます

でもインターン最優先!

『AtCoder Beginner Contest 126』A~CをPythonで解いた

けっこう久しぶりのはてぶです
定期的に書く習慣がつかないままフェードアウトしそうだったので慌てて書きました

第一印象

A:K文字目をlower()して切り貼りすればよさそう
B:if-elseの範囲分けを脳内でイメージしようとして無理で泣いた
C:例1が親切すぎて光明が見えた(のちに2つのWAを返していただくこととなる)
D:自分で7頂点の例作って考えてみたら塗分け出来なくて「???」ってなって終わった
E:完全に理解した、あとはプログラムにするだけだ(完全に理解していない)
F:10進数のXOR、そんなんもおったなぁそういえば(逃)

我ながら身の丈に合った3完と言えるでしょう...



A - Changing a Character

すべて英大文字の文字列のK番目だけを小文字にする問題

Pythonは文字列のインデックス指定ができるので
K文字目まで、K文字目を抜き出してlower()関数で小文字にしたやつ、K+1文字目以降
を貼り合わせます

n, k = map(int, input().split())
s = input()

print(s[:k-1] + s[k-1].lower() + s[k:])

B - YYMM or MMYY

長さ4の数字列がMMYY記法、YYMM記法になり得るかを判定する問題
キレイなif-elseの入れ子構造が分からず
前2桁、後ろ2桁がそれぞれ1-12か13-99かを見て「どちらにもなる」「MMYY」「YYMM」「どちらでもない」の4パターンを条件分としてべた書きしたところWA...
親切に例3に'1700'があるのに、'0012'のように00があってもイケる可能性を完全に見落としてました

s = input()
former, latter = int(s[:2]), int(s[2:])

if 1 <= former <= 12 and 1 <= latter <= 12:
  print('AMBIGUOUS')
elif 1 <= former <= 12 and (latter == 0 or 13 <= latter <= 99):
  print('MMYY')
elif (former == 0 or 13 <= former <= 99) and 1 <= latter <= 12:
  print('YYMM')
else:
  print('NA')

C - Dice and Coin

例1の説明が親切だったので方針がすぐ見えた方が他にもいらっしゃったと思います
N(サイコロのマックス目)がK(目標スコア)より小さい時
1からNまでの各出目ごとに、コインの表を出し続けなければならない回数を計算し、各目の確率を全て足し合わせていきます
NがKより大きい時
K以上の目を出せば一瞬で勝つので、K未満の目において上記の計算を行い、「K以上の目が出る確率」と足し合わせればよいです

n, k = map(int, input().split())

win_prob = 0

import math
if n < k:
  for i in range(1, n+1):
    win_prob += 0.5 ** math.ceil(math.log2(k / i))
  print(win_prob / n)
else:
  for i in range(1, k):
    win_prob += 0.5 ** math.ceil(math.log2(k / i))
  print(win_prob / n + (n - k + 1) / n)

例題では分数として計算し終わってから割り算して小数点にしていましたが、このやり方だと逐次的に小数を足していきます
競プロで誤差の許容範囲という概念に初めて出くわし、びびりながら書きましたが何ともなかったので良かったです


雑記

最近は東大の大学院を1年休学して(株)ABEJAでインターンしてます
マジで楽しいんですが、お笑い芸人かミュージシャンになりたいです
この話はまた近々書こうかな...

まだ競プロの勉強時間を全く取っていないので、レートが頭打ちになったら頑張ります

AtCoder Beginner Contest 124をPythonで解く

最近この時間はちゃんと予定を空けておくようにしています。

atcoder.jp

今日は40分でA、B、Cを解くことができたので初全完いけるんじゃね!?と思ったまま残り1時間を過ごし3完でした。残念。
自信を持ちながら過信しない、というのは難しいですね。

第一印象

A:簡単そうなのでキレイに書きたい(叶わず)(急いだ)
B:やっぱ先週のABCのA、B問題むずかったよな...
C:法則を見つけるんや!単純化や!核心を見つけるんや!(慣れてきている)(アルゴリズムとか問われたらどうする気なのか)
D:似たようなやつ見たことある(後述)(出来なかった)

という感じです。前回も書いたのですが苦痛になるのだけは避けたいので、全完より先に目指すは「安定してサクッと3完」ですかね。

今回からA、B問題については「本番中にわーっと書いて通した回答」に加え「終わってから落ち着いて考えたキレイバージョン」も思いつけば(AC通るか確認の後に)載せていきたいと思います。

続きを読む

AtCoder Beginner Contest 123で(2分足りず)2完でした

久しぶりに昨日ABCに参加することができました。
まだ2回のABCしか参加してないので灰色の下の方です。頑張らないといけないのですがTWICEの名古屋ドームライブが良すぎて、開始に遅刻した上にてんやわんやな回答をしてしまいました。

atcoder.jp

TWICEはとても良いので是非ハマってください。これは9人の良さ総合点が一番高い超神回です。
youtu.be


C問題でWA出てて終始唸ってたのですがギリギリに閃きました(間に合わず)。終わった2分後にAC通すことができたので悠長におにぎり食べてた時間...。
あと解説読んでみたら、本番中時間をかければDも解けたのでは、という感触なので復習も終わった後はマジで結構悔しかったです...。まあ終わってからでは何とでも言えますね。

いつもの第一印象

A:いつものAよりむずくない??
B:いつものBよりむずくない????
C:待機してる人>キャパ、の場所だけ注目すればいいのでは
D:愚直に実装するとTLEだ(ここがポイント)

ここがポイント!

計算量に関する先人のQiitaを少し読んでみたおかげで、「このくらいの数字ならこのくらい工夫しないとだめだな」みたいな考察か少し出来るようになっていました。D問題に立ち向かう意思と少しの力が芽生えたことを確認できて(結果はともかく)良かった回でした。

A - Five Antennas

直線状に並んだ5つの点のうち、距離kを超えてしまう2点はあるか、という問題。
愚直にすべて距離を計算するコードを自信満々で送ったら3つWAを出してしまい狼狽えました。落ち着いて再考することで「一番遠い2点の距離だけ見たらええやん」と気づいたので

  • 落ち着いて真に検証する必要があるポイントを捉えてからコード化に移ること
  • 考え及ばずな愚直実装であろうとせめてWAは出すなよ

という2つの再確認ができました。下はAC通った方のコードです。

input_list = [int(input()) for _ in range(6)]

poles = input_list[:-1]
k = input_list[-1]

if poles[-1] - poles[0] > k:
  print(':(')
else:
  print('Yay!')

Yayって何だ。

B - Five Dishes

最後の数字以外は一の位を切り上げる条件下で整数5つの最小和を求める問題。
今回のA問題とB問題、「出来るけどちょいしんどいな」っていう第一印象じゃなかったですか??

menu = [int(input()) for _ in range(5)]
mods = [food % 10 if food % 10 != 0 else 10 for food in menu ]
max_food = mods.index(min(mods))

times = 0

for i, food in enumerate(menu):
  if i == max_food or food % 10 == 0:
    times += food
  else:
    times += (food // 10 + 1) * 10
    
print(times)

後から時間に追われず見返すと「変数名...笑」とか「無駄な部分あるな...」とか「この変数結局使ってへんやん」とか反省します...。

C - Five Transportations

要約がムズい。
待機人数がキャパよりデカい場所でのみ、(待機人数)÷(キャパ)の商の数だけ多く時間かかるな、と初手で思いました。
例) 7人待ちで次の交通手段が3人しか乗れないなら7 // 3 = 2分よけいにかかる
この余計にかかった時間を5(=全員が一発で最初から最後まで移動できるときの所要時間)に加えればいいと考え実装してみたのですが、1/3ぐらいのケースでWA...。

終了2分前に「最初の人数」と「一番のボトルネックになる場所」だけ比較すればいいじゃん!という閃き虚しく100分経過で終了。
めちゃくちゃ悔しがりながらおにぎり片手に実装したのが下のコードです。

people = int(input())

ways = [int(input()) for _ in range(5)]

minimum = min(people, min(ways))

minutes = 5
if people % minimum == 0:
  minutes += people // minimum - 1
else:
  minutes += people // minimum
  
print(minutes)

この問題、いつもブログ読ませていただいているu++さんの回答がマジで良いので見てください。最近ただのファン。

upura.hatenablog.com

Bの回答もすげぇわ...。

D - Cake 123

3つの整数リストからそれぞれ1つずつ数を選んで取った和たちの中からデカい順にK個表示する、という問題。
この問題は少し計算量の話が見えやすい気がしますが
「各リストの長さがマックス1000だから全部計算してから並べなおして出力する愚直実装ではTLE食らうやつだ」
という見積もりが出来ました。始めたころを思い出すと勉強の成果を感じます。少しの成長も積極的に褒めていくスタイルで自分のペースを守りつつ頑張ります。

C問題で唸っていたので手を付けられませんでしたが、解説記事を読んで実装してみたらACでした!
初めてD問題で書いてみたコードをAC通せたのでとても満足です。

num_x, num_y, num_z, k = map(int, input().split())

x_list = sorted(list(map(int, input().split())))
y_list = sorted(list(map(int, input().split())))
z_list = sorted(list(map(int, input().split())))

xy_list = sorted([x + y for x in x_list for y in y_list], reverse=True)[:k]
xyz_list = sorted([xy + z for xy in xy_list for z in z_list], reverse=True)[:k]

for xyz in xyz_list:
  print(xyz)

まとめ

  • 実装に飛び移る前に「もう少し簡略化できないか」「もっと本質があるんじゃないか」と落ち着く
  • 愚直実装もせめてWAナシにしよう...
  • ABCは頑張れば全部解ける!と思い込んで4つの問題と100分向き合い続ける
  • 強い方のTwitterで見かけるPyPyって何?(まだ何も調べたりしてないので「ただ速い魔法のPython」だと思っている)