冷めたコーヒー

Weniger, aber besser

Twitter でアンケートした不等式の問題の解説

みなさま、ご無沙汰しております。みるか(@mirucaaura)です。90 日以上更新が途絶えてしまい申し訳ありません。近況などについてはまた後日にでも...。


Twitterのアンケート機能を利用して、次のような問題を投げてみました。

今回はこの問題の解説を行いたいと思うのですが、最近流行りのMathlogに書きましたので、そちらを参照していただければと存じます。

7月に読んだ本・読んでいる本

こんにちは、みるか(@mirucaaura)です。前回前々回に引き続き、今月に読んだ本について簡単にまとめておきたいと思います。

プログラマが知るべき97のこと

プログラマが知るべき97のこと

プログラマが知るべき97のこと

  • 発売日: 2010/12/18
  • メディア: 単行本(ソフトカバー)

先月、本書の監修者である t_wada さんこと和田卓人さんのご講演を拝聴する機会があり、本書を知りました。ご講演のログについては以下の記事にまとめましたので、ぜひ目を通していただければ幸いです。

mirucacule.hatenablog.com

本書は、題目の通り、プログラマが知っておくべき事柄について、著名なプログラマによる 97 本のエッセイによって構成されています。また、日本語訳版では、Ruby開発者であるまつもとひろゆきさんや t_wada さんによる 10 本のエッセイも加わっています。

内容については本書に譲りますが、ぜひ読んでみたくなるようなエッセイタイトルを以下に列挙しておきます:

  • 関数型プログラミングを学ぶことの重要性(Edward Garson; pp4-5)
  • ハードワークは報われない(Olve Maudal; pp.72-73)
  • 車輪の再発明の効用(Jason P. Sage; pp.138-139)
  • シングルトンパターンの誘惑に負けない(Sam Saariste; pp.140-141)
  • エラーがエラーを相殺してしまう(Allan Kelly; pp.162-163)
  • 正しいアルゴリズムとデータ構造を選ぶ(Jan Christiaan "JC" van Winkel; pp.168-169)
  • WETなシステムはボトルネックが見つかりにくい(Kirk Pepperdine; pp.172-173)

一つひとつのエッセイは見開き 2 ページ程度であり、それぞれが互いに独立した内容なので、隙間時間などに少しずつ読むのに適しています。

エッセンシャル思考

再読しました。前回読んだのが2月だったので、およそ5ヶ月振りとなります。本書のキーメッセージは「より少なく、しかしより良く」という一点に集約されます。色んなことに手を出して全てを中途半端に終わらせるのではなく、自分がすべきことを徹底的に明確にして、そこで最高の結果が出すことが人生のあらゆる場面で重要となります。本書は、本当に重要なことを見極め、それを確実に実行するための方法論について、エッセンシャル思考の人と非エッセンシャル思考の人との比較を通して伝えています。以下の表は両者の《考え方行動結果》に関する比較を表したものです。

非エッセンシャル思考 エッセンシャル思考
やらなくては これをやろう
どれも大事だ 大事なことは少ない
全部こなすには? 何を捨てるべき?
差し迫ったものからやる 本当に重要なことを見定める
反射的に「やります」と言う 大事なこと以外断る
期限が迫ると根性で頑張る1 予め障害を取り除いておく
何もかも中途半端 質の高い仕事ができる
振り回されている コントロールしている
疲れきっている 毎日を楽しんでいる

本書の内容は書かれていることを理解するだけであれば極めて簡単だと思います。しかしながら、それらを日々の生活の中で実践することは一朝一夕には難しいと思います。自身の生活に取り入れたい Tips を一つ選んで実践し、無意識でも実践できるようになったら本書を見返して再び生活に取り入れて...というサイクルを繰り返していくとよいと思います。

シンプルな勉強法

シンプルな勉強法というタイトルの通り、奇を衒ったような内容については一切記載されておらず、正統的な勉強の仕方に関する本です。大学受験に関連した事例や具体例が多く、多少のくどさを感じましたが、これから大学受験を控えている高校生のみならず、大学受験を終えた大学生や社会人が読んでも得るものはあると思いました。幾つか役に立ちそうな内容をメモしておきます:

  • 勉強を通して、何らかの目標を達成したい場合、「どれくらい頑張ったか」と「どの方向に向かって頑張ったのか」の二軸が重要となる。次の逆算的な思考を行うことで、誤った方向に努力してしまうことを避ける:
    • 目標を定め、具体的なゴールを設定する
    • ゴールまでにやりたいことを決める
    • やるべきことをスケジュールに落とし込む
    • 実践する
    • 進み具合を定期的に確認する
  • 動画で何かを学ぶ際は、全体像のメリハリをつけるために、ある程度視聴したら一時停止してそれまでの内容についてメモをする。逐次、情報を頭の中で整理してアウトプットをしていくことが重要。
  • 家の中で勉強に集中ができないときは、スマホを家に置いて、自宅から少し離れたカフェや図書館で勉強をする。スマホを放置することで、勉強以外にできることをなくすことが大事。

デジタルネイチャー

2年ほど放置していましたが重い腰を上げて読んでみました。本書で唱えられている「デジタルネイチャー」というのは、人間を数理的に捉えるウィーナーの「サイバネティクス」と、あらゆるモノにコンピュータ性を付与するワイザーの「ユビキタス」という二つの概念を継承した計算機分野の思想のことだそうです(pp.87)。

AI分野の研究に携わったことがないので知らなかったのですが、今AIの分野で求められている才能は、データとデータの間の関係性に目を向けるセンスであり、必ずしも解析的な発想が求められないということです(pp.84-85)。頭で考えるよりも、データセットと(既存の)解析手法と計算機資源があれば新規性が出せる(可能性がある)という点は理論的な分野に携わっていた自分としては新鮮でした。

本書の内容は機知に富んでいる一方で、敢えて分かりにくい専門用語や衒学的表現を多用している印象を受けました。この文体こそ著者特有の文体であり、そこに楽しみを感じる読者が一定数いることも事実だと思う。しかしながら、個人的には、もっと平易な文体で読みたかったです。

解析入門Ⅰ

軽装版 解析入門〈1〉

軽装版 解析入門〈1〉

第一章:実数を中心に読みました。これまで実数は既知として扱ってきましたが、本書にもあるように、現代数学の立場から見ると高校までに学んだ実数の認識では厳密性に欠ける点があります。そこで、有理数については既知として、それに基づいて論理的に厳密な実数論を構築することが本章の目的でした。補助資料として、YouTube にアップロードされている動画を参考にしながら進めました。議論を進めるに当たって、ε-N論法を用いる場面が多々ありますが、この概念に慣れるためにはε-N論法について考え込むよりも、例題や諸定理の証明を通して慣れていけば良いというのが個人の見解です。

おまけ

余談として、今月やっていたことについて少しだけ触れておきたいと思います。

数学に関しては、前述した通り、解析学の実数論について学びました。補助資料として用いた動画は、古賀さんの動画AKITOさんの動画です。今回に限っては、より厳密な議論について学びたかったのでヨビノリさんの動画は視聴しませんでした1。勉強の進め方としては、学んだ内容を自分で再構成できるレベルを目指しています。

数学以外で時間を割いたこととして、筋トレを継続的に行いました。我流でやっても大した成果は生まれないと思ったので、コチラの動画を参考に、完走できることを目指しました。現在、何とか 3 分を超えることができるようになりましたが、完走には至っていないので、来月も継続して取り組みたいと思います。下図はログです。横軸が回数、縦軸が秒数を表しています。

f:id:mirucacule:20200729112948p:plain
筋トレ精進グラフ

他には、競プロにも時間を割きましたが、ABCのE問題以降を解けるビジョンが見えずに行き詰まっています。より具体的に言うと、AtCoder Problemsにおける緑色上位レベル〜水色下位レベル以上の問題に対する解法を自力で思い付くことができない状態です。圧倒的に演習量が足りていないことが要因の一つであることは間違いないので、典型とされる問題をストックしていく必要がありそうです。

また、4連休(7/23~7/26)で心に余裕があったので、株式や確定拠出年金、税金などといったお金まわりのことについて学びました。それに伴って、会計の知識を身に付けたくなりました。以前、簿記の勉強をしたことがあるのですが、機械的な仕訳の作業に終始してしまい、面白みを見出せませんでした。Twitter2にて、より厳密な立場で会計について学べる書籍について質問したところ、以下の書籍を紹介していただきました。書店で気に入ったものを購入したいと思います。


  1. このやり方はやってしまいがちですが、再現性のない確率的な仕事になってしまうので、気を付けたいです。

  2. ヨビノリさんの動画が厳密性に欠けるという意味ではありません。悪しからず。

  3. 当該ツイートへのリンクです。ご回答して頂いた方々、誠にありがとうございました。

6 月に読んだ本・読んでいる本

こんにちは、みるか(@mirucaaura)です。先月に引き続き、今月に読んだ本・読んでいる本を簡単にまとめておきたいと思います。前回の記事は以下になります。

mirucacule.hatenablog.com

リーダブルコード

再読しました。前回読んだときはMATLAB数値計算を我流で書いていたくらいで、本書に書かれていることは理解できるけど、実践する機会があまりないような状況でした。最近は共同で開発を行うこともあったり、今後もよりそのような機会が増えてくることが考えられるので改めて読んでおこうと思ったことが再読をしようと思った経緯です。本書を読んだからと言ってすぐに良いコードが書けるようになるわけではないことは自明ですが、書かれている内容については実践すべきことばかりなので、脳死レベルで「すべきでないコードの書き方をしない」ことを念頭に日頃からコーディングをしたいです。

SCRUM BOOTCAMP

アジャイル開発手法の一つであるスクラムについてストーリーベースで解説された書籍。スクラムのルールとしては、スクラムガイドで定義されおり、本書の内容は2017年版のスクラムガイドをもとに説明がなされています。当たり前なことですが、書かれている内容を理解することと実現場で実践することの間には大きなギャップがあります。幸いにも、現在アジャイル開発を経験することのできる機会を与えられているので、本書の内容を意識しながら学んでいきたいです。

コンピュータシステムの理論と実践

第2章途中まで。5月末に届いたのですが、全然進んでいません。内容が難しいというよりも、本書で推奨されている「ハードウェアシミュレータを用いて回路をHDL言語で実装を行いながら読み進める」という方針を採用すると非常に時間がかかってしまうことが要因であると思われます。一度ざっと通読してから実装段階に入った方がいいのかもしれません。

初めてのSQL

初めてのSQL

初めてのSQL

基本的な操作をUdemyを受講して学んだので、リファレンスできる本を手元に持っておきたいと思い購入しました。Udemyでは、paiza.ioFiddleを用いることによってローカル環境に実行環境を整えることなく操作することができて楽でした。

からだ図鑑

世界一やさしい! からだ図鑑 キャラでたのしく解剖生理!

世界一やさしい! からだ図鑑 キャラでたのしく解剖生理!

  • 発売日: 2018/02/01
  • メディア: 単行本(ソフトカバー)

Kindle本。生物未履修なので自分の体のことくらい知っておきたいと思って読みました。本書は、人間の体の中で働き続けている細胞や各器官の基本的なメカニズムを理解し、病気の予防や治療への入り口として役立ててもらうことを目的としています。タイトルに図鑑と付いている通り、イラスト豊富で極めて読みやすかったです。パラパラとページを捲るだけで楽しい一冊でした。主な内容を列挙すると、細胞・消化器系・循環器系・泌尿器系・内分泌系・生殖器系・脳神経系・感覚器系・筋骨格系・呼吸器系です。

栄養素図鑑

世界一やさしい! 栄養素図鑑

世界一やさしい! 栄養素図鑑

  • 発売日: 2016/09/15
  • メディア: 単行本

からだ図鑑の栄養素版。こちらもKindle本。筋トレをするようになって、意識的にタンパク質を摂取したり、頭の働きを活発に保つためにどの栄養素が重要でどんな食事を摂ればよいのか、などのことを知りたくて読みました。本書も図鑑よろしく、イラスト・写真・漫画などが豊富で読みやすい構成となっています。主に、三大栄養素・食物繊維・ビタミン・ミネラル・機能性成分について扱われています。

目からウロコのコーチン

チームで作業を行うことが増えてきたし、今後も増えてくることが予想されるので、一度コーチングについて学んでおくことは有益であろうと思って購入しておきました(まだ読んでいない)。コーチングはもともとkobaka7さんのツイートをきっかけに興味を持っていたのですが、具体的にコーチングを受けたり学んだりしたことはありませんでした。他人にコーチングを行うことによって、その人が目標に向かって行動を促すことがよくあるシナリオだと思うのですが、何も他人だけに使える技術ではなく、自分自身のマインドセットの構築にも大きな役割を果たす技術であると思います。

note.com

おわりに

本当は受講していた映像授業についてもまとめておきたかったのですが、このページで行うと煩雑になってしまうと思ったので、別の機会に取り上げたいと思います。

t_wada さんの講演メモ ー 技術書の読み方を中心に

はじめに

和田さん(@t_wada)の講演が素晴らしく良かったのでメモを残しておきたいと思います。和田さんと言えば...

f:id:mirucacule:20200623200436j:plain
t_wada

ですね!本講演では、「技術の学び方を学ぶ」ことを目的として二部構成で論が展開されました。「技術の学び方の学び」とは、メタレベルの学びのことを指しています。すなわち、効率的に新しい技術を学ぶためにはどのように学べば良いのかという話です。内容は以下の通りです。

  • 第一部

    • 四半期ごとに技術書を読む
    • 手を動かしながら学ぶ
    • 毎年少なくとも一つの言語を学ぶ
    • 身の回りをプログラミング対象にする
    • アウトプットを行う
  • 第二部

    • 毎日コードを書く
    • 年下から学ぶ
    • 過去から未来を見る
    • 人のつくる渦を見る
    • 大事なことに集中する

いずれも非常に興味深い内容だったのですが、細かい事項については2017年の講演メモのエントリーがありましたので、ぜひそちらをご覧いただければと思います。(記事へのリンク

本エントリーでは、以下の2点について深く取り上げたいと思います。

  • 技術書の読み方
  • アウトプットの仕方

本を読む目的

技術書を読む目的は主に2つ:

  • 自分の脳内にインデックスを作る
  • 書かれている内容について習熟する

「自分の脳内にインデックスを作る」というのは「この本にはこんなことが書いてあったな」というインデックスを脳内に作り、書かれている内容については忘れてしまう(覚えているに越したことはないのですが、人間そんなにうまくできていない)ということです。書かれている内容について習熟することは一般的な本を読む目的として知られていることと思います。

脳内にインデックスを作ることの効用は書くまでもないかもしれませんが、これを作っておくことで、その技術が必要になったときに即座にアクセスできることはもちろん、どの技術を用いてどんなことができるのかを知ることができる点にあります。車輪の再発明を避けることができますね。

本の読み方

先にも述べた通り、本を読む目的は2つありました。インデックスを作ることが目的であれば、短時間でサラッと読めばいいのですが、深く読み込むためにはそれなりに工夫が必要です。本講演で和田さんは「写経」することを勧めていました。写経の手順は以下のツイートの通りです。

いいですね。もちろん、すべての本に対してこの方法をとっていては時間が幾らあっても足りませんので、身に付けたい技術を絞り、本も定番とされているものを一冊決めてじっくり読み込むことを推奨していました。

アウトプットの仕方

インプット型の学びは極めて楽です。しかしながら、受け身で学んだ内容が身に付きにくいことは周知の通りです(Ref:デールの円錐)。新しい技術を学んだのであれば、その技術を全くの初心者に対して理解させることを目指すべきだし、新しいプログラミング言語を学んだのであれば、その言語を用いてまっさらな状態から何かしら自分の困っていることを解決するためのツールを作ることを目指すべきです1

したがって、何らかの方法でアウトプットを行うことが肝要なわけです。手法は様々だと思いますが、既存のサービスを使うのがいいと思いますし、@t_wadaさんも以下のようなサービスをアウトプットのチャネルとしてお勧めされていました。

  • Twitter
  • Qiita
  • GitHub
  • 雑誌記事(Web,紙媒体、電子書籍
  • 書籍(共著、翻訳、監訳、単著)
  • 講演(社内勉強会、社外講演)

ここでの注意点として、文書でアウトプットを行う場合はflow型であるTwitterなどのチャネルよりも、stock型のblogQiitaに投稿した方が良いということです。最大瞬間風速が重要となるflow型のサービス(e.g.,Twitter)は一時的にバズりやすく快感を伴います(?)が、後からその内容を検索することが困難です2。もちろん、まずはTwitterでラフに考えていることを記述しておいて、その後にhatenablogなどでしっかり記述するというやり方はアリだと思います(わたしはよくやります)。

また、初心者には敷居が高いという件に関してですが、もちろん誤った情報を公開してしまうことはなるべき避けたいわけですが、初心者は初心者ならではの価値を提供できます。どういうことかと言うと、初心者は経験者が気付けないようなハマりポイントを取り上げることができます。経験年数が上がれば上がるほど、初心者がどんなことに躓くのかが分からなくなってしまうということは少なくないかと思います。なので、詳細かつ省略をせずに行ったことを記載することから始めていけば良いという意見でした。

最後に、勇気付けられる引用を。

情報発信、blog,発表、公開などは数学の未解決問題の証明ではなく、料理のようなもの

Jenkins 開発者である川口耕介さんの言葉だそうです。私たちが公開しようとしているものは、学術論文ではありません。新規性がなくてもいいのです。査読もありません。気楽にいきましょう。再現性は担保しましょう。

おわりに

(わたしのTwitterをフォローしていただいている方には分かるかと思いますが)学ぶべき事項が多すぎるあまり、気の焦りから様々なことに手を出して全てが中途半端になってしまっているような状況がここ最近ずっと続いていました。何から手を付けたらよいのか、何に焦点を当てればよいのか、何に集中すべきなのか、そういったことが脳内をグルグルし続け、精神が疲弊していました。このことを最後のQ&Aで質問したところ、次のような回答を得られました。

最初の数年のうちは、私はこれでいいと思っています。色んなことに手を出して中途半端になるということは、その内容が自分にとってそこまで気を引かれるものではないからかもしれません。だから、発散フェーズにいるうちは、色んなことに手を出して良いと思っています。今のうちにリッチなWebデザインや機械学習に手を出してみたり、Androidのアプリを作ってみたり、新しい言語に触ってみたり、色んなことに手を伸ばすことは若いうちはいいことだと思います。(対象を絞るのは、)気を引かれる技術があれば、今年はこれをやろうと決めて取り組んでもいいし、Thought WorksTechnology Radarを見たりして、今は興味はないけど、これから流行るであろう言語をやるでもいいと思います。やっていくうちに段々と好きになり習熟度が上がることはよくあることだと思います。


色んなことに手を出して全てが中途半端になることは悪いことではないと思っています。手を出してみたことを例えばブログなどに記録していけばそれも大きな価値を伴います。途中までやったことを数年後に再開することもザラにあります。色んなものを摘み食いしていくうちに、面白いと感じるものや自分が手を動かしているうちに「なるほど、これは面白いな」と思えるような技術が幾つか出てくると思うので、それらを専門性として育てていけば十分だと思います。


また、色々と削減していかなければならないフェーズは、もっとベテランになってきたりライフステージが変わってきたりしたときで、そうなるまでに色んなものを食べておけば、様々な道具が自分の道具箱に入っていると思うのでより生き残りやすくなると思います。

このタイミングで@t_wadaさんの話を伺うことができて本当によかったです。


  1. べき論で言えばそれはそうなのですが、これはなかなかできないですよね…。

  2. 最近になって「from:@userid keyword」のような検索の仕方がユーザによってできなくなっていて困っています…。何かご存知の方がいらっしゃいましたら教えてください。

yukicoder No.1077「Noelちゃんと星々4」in Python

問題

点が $N$ 個あたえられます.点 $i$ の高さは $Y_i$ です.Noel ちゃんは点の高さを自由に動かせます.ある日Noelちゃんは,点の高さが広義単調増加になるように点を動かしたくなりました.Noel ちゃんが動かす必要のある距離の総和の最小値を求めてください.ただし Noel ちゃんは,どの点も整数の距離だけしか高さを変えられないものとします.

要するに,与えられた数列を広義単調増加にしてください,という問題.

制約

  • $1 \leqq N \leqq 10^{3}$
  • $0 \leqq Y_i \leqq 10^{4}$

解法

dpで解く.配列は,$(N + 1) \times (\max\{Y\} + 1)$ の二次元配列として持つ.また,dp 配列の第 $(i, j)$ 要素は次のように定義される.

dp[i][j]:数列 $Y_0,Y_1,\dots,Y_{i-1}$ が広義単調増加となるように点の移動が完了しているとき,$Y_i$ を $j$ にしたときに必要なコストの最小値

※ ある数列 $\{A_i\}$ が広義単調増加であるとき,第 $i$ 番目の要素を $x$ としたとき,それ以前の要素($A_0, A_1, \dots, A_{i-1}$)はすべて $x$ 以下である.

したがって,遷移の仕方は次のように表せる.

$$ \mathrm{dp}[i][j] = \min_{0 \leqq k \leqq j} \{ \mathrm{dp}[i-1][k] \} + | Y_i - j | $$

添字に注意して実装してあげると,以下のようになる.

n = int(input())
Y = list(map(int, input().split())) # 0-index
mx = max(Y)
INF = 10 ** 18
dp = [[INF] * (mx + 1) for _ in range(n)]
# i = 0 のときを埋める
for j in range(mx + 1):
    dp[0][j] = abs(Y[0] - j)
# i >= 1 の場合を埋める
for i in range(1, n):
    mn = 10 ** 18
    for j in range(mx + 1):
        mn = min(mn, dp[i - 1][j])
        dp[i][j] = mn + abs(Y[i] - j)

print(min(dp[-1]))

入力

6
1 2 0 8 6 9

結果(実行後のdp配列)

for v in dp: print(v)
# 以下ターミナル上での出力
[1, 0, 1, 2, 3, 4, 5, 6, 7, 8]
[3, 1, 0, 1, 2, 3, 4, 5, 6, 7]
[3, 2, 2, 3, 4, 5, 6, 7, 8, 9]
[11, 9, 8, 7, 6, 5, 4, 3, 2, 3]
[17, 14, 12, 10, 8, 6, 4, 4, 4, 5]
[26, 22, 19, 16, 13, 10, 7, 6, 5, 4]