/ 最近 .rdf 追記 設定 本棚

脳log[2020-12-19~]



2020年12月19日 (土) メールアドレスを到着確認せず会員登録できるサービス、誤登録された被害者にメールアドレスの変更を提案 | スラド IT」このコメントに完全に同意する>「メルマガ解除にログインが必要っていうのがおかしい」■たとえ使い捨て URL を使ってメールの疎通確認をしていたところで、それは「その時点において」登録者がメール受信能力を有していると判断されるに過ぎない。だから不要な、心当たりのないメールを受信した事実を持って、購読を停止させる権限を認めるべきなんだ。現在が過去に優先する。そこにログインは関係しない。メールを送信する者は常に自身がスパマー同然のふるまいをしていないかを確かめないといけない。自分とこのサービスにアカウントを作って利用している者とメールの受信者が別人なら、お前はスパマーだ。その可能性を考えずにログインしてメールの購読を解除するよう要請するのは間違っている。日本の事業者の仕組みが遅れているのが目につくのもコメントに書かれている通り。■ところで「ワンタイムURLのような機能が無いのであれば、同じアドレスで登録されないようにと希望したが、弊社では対策ができない」として断られたという話。これは妥当に思える。メールアドレスの現在の所有者であることをもって未来を縛ろうとする行為だから、認めると別の問題が生じるのでは? とはいえこれ同然の問題は今ある問題なんだよなあ>「Webサイトのフォームで悪用被害急増中!加害者にならないためのフォーム設置講座 | さくらのホームページ教室


2020年12月16日 (水) すごいんですよーと紹介しながらその機序や根拠を「特殊な~」「特別な~」といった表現で説明するの、つまりは説明を放棄するの、やめて欲しい。「なんかわからんけどすごいんだな」というのは視聴者の感想であって、紹介する側が最初から「なんも説明せんけどすごいんだぞ」と言って終わらせるの、とても満足できない。まあ、通りがかりに目に入るだけでわざわざ(不満を垂れながら)見るわけではないんだけど。■しかし逆に健康や食品に関することだとあれやこれやの物質名を出して、物質の性質なのか、動物への作用なのか、人間への作用なのか知らないけど、事細かに可能性のある効能を並べ立てるということがあるのかな。そっちの分野になると俺はおいしいもの食べたいものを食べて死ぬべきときに死ねばいいと思って興味が湧かないんだけど。■原因から良い結果を期待するには人体は複雑だし個人差がありすぎると思う。自分に何が不足していて何が必要か、自分の体に聞かないで一般的な傾向を聞いてどうする。自分の体に現れる徴候をモニタリングするのが第一で、それから悪い傾向に原因を見出すのがいいんじゃないかと思う。それが人生の楽しみだというなら盲目的に際限のない健康ゲームをするのも結構だけど。


2020年12月15日 (火) [AtCoder] おとといあった ABC185 の解けなかった E 問題。ちらりと見かけたツイートの LCS という語が、LIS (Longest Increasing Subsequence) に似た Longest Common Subsequence の略なんだろうなと予想できる程度には目途が立っているのだけど、「さて LCS (の長さ)を求めるには……。……。」というのが今の状況。LIS のときは首尾良くいったんだけどな>20200602p01。■cherish という語はひと目で忘れられなくなった印象深い意味を持つ動詞。


2020年12月10日 (木) 「手を動かす」と「先に実装する」はニュアンスが違うと思うんだよね。対象にもよるだろうけどプログラミングの場合は典型的で、雑に手を動かせば壊れる。「実装する」に「動く(機能する)ものを~」が含意されていることを見落としてはいけないと思う。あと「人手があればできるから、先に実装したやつが偉い」には異なる読みも可能だと思う。つまり、「誰でもできるなら誰がやったかには意味がない。何に価値があるか。何をやり何をやらないかの判断こそ重要。」 ここでは「実装する」に「価値あるものを~」が含意されている。このような暗黙の前提を忘れて「ただ手を動かす」ことに価値を置くと評価と行動を誤る。貢献ではなく迷惑なだけの功名争いになる。実装能力、判断能力に劣り、誰でもできることが当たり前にできない者は、否応なく前提を無視してただ手を動かすことに価値を置く。そこにしか拠り所がない。だから前提は暗黙のままにしておけない。


2020年12月08日 (火) [BOOX Max2] 家で読むのは持ち歩きに不便な大判の本、雑誌か、BOOX Max2 に入れた自炊本のどちらかになりました。外とお風呂では Sony Reader (PRS-650) です。自炊本ライブラリは 4545 冊、381 GiB になりました。ScanSnap S1500 の総スキャン回数は 561881 回でした。■ BOOX Max2 の Firmware V3.0 が 今月の頭に降ってきたのでアップデートした。半年前のバージョンで見開き表示の左右入れ替えなど基本的な機能は揃っていたので今回は完成度を高めるリファインという感じか。なので、あえて些細な不満を2点書く。十分に満足しているので他に書くことがない。■1点目。接続端子が USB と HDMI とイヤフォンの3つあるんだけど、充電にも使う USB 端子が最重要。これが短辺の中央よりやや片側に寄った位置にあるせいで、手探りでテキトーに差すことができない。良いことか悪いことかはともかく2から3センチはある幅広のベゼルに囲まれているので、USB 端子の位置を示すようにシールを貼った。おかげで端子を目で確認せずとも難なくケーブルが差せる。これは自分の工夫で何とかなる不都合。■2点目。ページの進捗を示すと同時にシークも行えるバーが利用できるのだけど、バーの右端に「ページ番号/総ページ数」が表示されている。これは進捗をデジタルに知ることができる重要な指標であるし、タップすることで直接ページ番号を指定して移動することができる必要なツールでもあるが、バーの左側には同じようなものが存在しないということが微妙な問題を生む。1点目の問題と似るのだけど、50 % の進捗度合いのときにプログレスバー兼シークバーのつまみが画面の中央に来ない。バーの左端と右端が画面の端から等距離にないからそうなる。■人間は機械じゃないから感覚は大事。微妙なズレを常に意識することも正確に補正することもできない。機械の側で感覚を裏切らないようにしてくれないと不都合が生じる。……というような不満しか出てこないくらいに不満なく日常的に使用している。■■■@2020-12-15 どうやら Sony Reader に差していた microSDHC(32GB) が限界を迎えていたらしい。数 GB の空きがあるにも関わらず最近ちょくちょく読書履歴(cacheExt.xml)の更新に失敗していたし、今日はとうとう全く書き込みができなくなった。現象がどういう風に現れたかというと、チェックディスクを実行すると何度でもファイルシステム(FAT32)エラーが修復されて、ファイルの断片がサルベージされる。内容を見ると cacheExt.xml(約800KiB) と cache.xml(約300KiB) と最近読んだ本のサムネイルだった。これらは更新頻度が高いファイルと最近生成されたファイル。クイックフォーマットをしようとして何度も失敗し、やっと成功して中身が空になってもチェックディスクでファイルがサルベージされる、のみならずフォーマットして消えたはずのすべてのファイルが元のディレクトリ構造を保ったまま現れた。クイックでないフォーマットをしてもやはり一度は消えたように見えたファイルが現れたし、壊れたファイルシステムが修復され続けた。つい半月前(20201128p01)に初導入した SSD もこういう風に限界を迎えるのかな。■壊れたものを 64 GB の microSDHC(FAT32) に差し替えたので、もう1スロットの 128 GB と合わせて Sony Reader には 192 GB の記憶容量。BOOX Max2 は解像度が高いにも関わらず内蔵の 64 GB だけだから全然及ばないし、いつでもどの本でも読み返せるというわけにはいかないね。


2020年12月07日 (月) [Ruby] 2.7. 配列の複製。a.dup と *a の比較で dup の方が速いと書くツイートを読んだが、dup の速さは copy on write 的な速さじゃないかと疑問に思った。テストスクリプト>a.rb。速い順> dup > *A& > dup& > *A。タイム> 0.0003 > 8.0 > 8.2 > 8.4。書き込みまで含めれば dup も速くない。順番を入れ替えたりしても一貫して *A (ただの複製) より *A& (複製&代入) の方が速いのが謎であり何か失敗しているのかもしれないが……。■別バージョン>b.rb。配列のサイズと繰り返し回数の大小を入れ替えたもの。速い順> dup > *A > *A& > dup&。タイム> 0.3 > 2.5 > 2.5 > 3.2。おそらくコピーをツケにしている dup はさておき、dup& の劣勢が明らか。コピーすべき配列のサイズが小さい反面、Array#dup の呼び出し回数がかさんだことが理由では? *A はメソッド呼び出しではなくて文法的なアレ(←語彙力)だったりする(かもしれない)のが有利なのでは? 文法といえば while 文ですが……(while は速い)。■Array#dup が速いのは嬉しい。たとえば配列を更新しながら何度も yield するとき>20190907p01.03。yield された方で破壊的変更を加えたときにメソッドの継続に支障を来してはいけないが、メソッドの使用方法に注意書きを添えるのでは不十分。かといって都度都度配列のコピーを yield するのも、ほとんどの場合には無駄となる。本当に必要になるまでコピーが遅延されるなら嬉しい。「~なら」って書くのは、実際のところ https://github.com/ruby/ruby/blob/master/array.c#L2654 からコールグラフを辿っていってもよくわからないから、っていうか本当にコピーしているようにしか見えないからなんだけど。■array.c の末尾を見ると Array#dup の実体が rb_ary_dup だという事実はなさそう。object.c を見ると dup の実体は rb_obj_dup らしい。そこのコメントを読むとこの(dup)メソッドはクラスごとに固有のふるまいを見せるだろうから、クラスの initialize_copy メソッドのドキュメントを読むんだよ、と書いてある。再び array.c に戻って Array#initialize_copy の実体が rb_ary_replace であることを確認するんだけど、それではなくて rb_ary_shared_with_p のコメントを読むとこうある。「このメソッドは、たとえば rb_ary_replace において、配列のスナップショットがとられて、それから変更が加えられたかどうかのチェックに使われる。スナップショットは安いがスナップショットに変更を加えたときにはコピーのコストが発生する。pop, shift を呼ぶかぎりにおいては配列の共有は維持される。」みたいな。■Array#dup の実体がどれだかちょっと曖昧だけど、配列の全体なり部分なりを共有してコピーを先送りする仕組みがあるのは間違いない。


2020年12月06日 (日)

最終更新: 2020-12-08T16:28+0900

[AtCoder] 鹿島建設プログラミングコンテスト2020(AtCoder Regular Contest 110)/A,B,C

ARC 級の企業コンであることがわかりやすい表記になった。企業コンだけどいつもの ARC と同じ気構えで挑戦してもいいことがわかりやすい表記になった。

鹿島の名前はブルーバックスの『図解 超高層ビルのしくみ 建設から解体までの全技術』の編者としてと2冊の SD 選書『近代建築の失敗(著:ピーター ブレイク)』『建物のあいだのアクティビティ(著:ヤン ゲール)』の出版社(鹿島出版会)としてだけ目にしたことがある。ジャンルが同じだから関連があるのでは?

 A 問題 Redundant Redundancy

題意を満たすような数のうち脳死で求められるものはすべての数の積+1なんだけど、答えに制約があって N 以上 10^{13} 以下のものを出力しなさいと。

2 から N の数を素因数分解してマージする。素因数がそれぞれいくつあれば 2 から N の数を表現するのに足りるのか。16 なら 2 が 4 つ必要だし、27 なら 3 が 3 つ必要。6 や 18 など複数の素因数を持つ数はとくに考えなくていいかな。

 提出 #18579266 (AC)

ひょっとして求めたものを最小公倍数と呼ぶのだろうか。Integer#prime? なんて便利メソッドを使ってごにょごにょするくらいなら Integer#lcm を使うのが直接的だったんだろうか。

 B 問題 Many 110

入力例1の解説を注意深く読めばわかるはずですが、注意すべき点があります。110 を 100 個連結した文字列の中に、110110 という部分文字列は 99 個見つけることができます。決して 50 個ではありません。

この勘違いを正すのに多大な時間を要した。難しい問題ではないとわかるのに答えが全然合わなくて、神経衰弱になりそうだった。

 提出 #18593923 (AC)

とりあえず答えは出た。

 C 問題 Exoswap

前回より悪くて(20201202p01.04)、3問目にして 20 分しか時間が残っていなかったけど、考えるだけ考えた。

  1. 同じ操作が高々1度しか許されていないので、ある数を適正な位置に移動するのに冗長な操作は許されない。
  2. まずは数ごとに必要な操作の列を作った。
  3. すべての数を満足させるよう操作の順番がひっくり返らないようにしながら、すべての操作列を一列にマージすれば良さそう。
  4. 行きすぎて戻るということはできないから、操作が少なくて済む場合は即座に NG。
  5. 同じ操作を要求する3つ目の数があれば、それも即 NG。
 提出 #18611107 (TLE×6 / AC×56)

TLE です。メモリの使用量に比例した時間がかかっているような雰囲気。testcase_10.txt は提出によっては TLE にならないことがあり、TLE といえども 22xx ms ではなく 20xx ms であるあたりちょうどボーダーライン上のケースだといえる。そのメモリ使用量が 560 MB。その他の TLE は 570 MB から 632 MB のメモリを使用している。全然ダメって感じではなくて何割か改善したら AC になりそうな期待が、ないかなあ。

特に頭の悪いことをしている部分があるとは思わないんだけど、だからこそ、根本から発想の転換が必要だと言われたら困るなあ。

大量のメモリって、前半の操作列の列挙部分で使ってるのかなあ。見え見えのダメケースを前半部分で拒絶するべきなのかなあ。さっき書いた「同じ操作を要求する3つ目の数があれば、それも即 NG。」とか、今考えたけど「i,i+1 という操作と i+1,i という操作を要求する2数があれば、操作列のマージが不可能なので NG。」とか。

前半部分の列挙について考えていると、後半部分のキューが不要にできそうな気がしてくるなあ。問題の制約って想像よりかなり厳しくて、可能なケースが限られるし、可能な操作列もいくつか考えられる中から一番簡単なものを出力するのに手間はかからなそう。

つまり、数列に対応した(※)配列に右向き左向きをメモして、山と谷があって、高いところ(流れの発するところ)から低いところ(流れの集まるところ)へ向かってテキトーな順番で列挙するだけなのではないかという……。

※数に対応させるのか数と数の間に対応させるのかで迷ってコードにならない。今は「間」かなという気がしている。

 提出 #18639675 (AC / 424 ms)

とりとめなくいろいろ書いたけど、結局、前半部で見え見えのダメケースを拒絶して AC になった。

もっと鮮やかに解けるはずなんだけど、当面のモチベーションは消えてしまった。


2020年12月02日 (水)

最終更新: 2020-12-03T19:37+0900

[AtCoder] AtCoder Regular Contest 109/A,B,C,D

先月28日土曜日の振り返り。ARC なので A 問題が 300 点からスタートする。2問解けたらまあまあという感じ。配点が同じ 300 点、400 点でも、ABC のと比べるとちょっと手強い印象を持っている。

時間は長めの2時間。ABC と違って C、D、E、F 問題にはだいたい取り付く島さえないので、時間が足りなくなるということはまずない。簡単すぎるテストと難しすぎるテストは時間が余るという点で共通する。

 A 問題 Hands

上の階に上がるのに階段と廊下の2種類の手段があるというのが不思議な設定だが、床の高さが半階分ずれた2棟が上りと下りのスロープで結ばれていると解釈するツイートを読んだ。なるほど。ところですべてのフロアが渡り廊下で連結されているなら、それも水平1本ではなく三角形で繋がっているなら、2棟は一体の構造物として設計されているのでは? そのとき「廊下」はどのような形態になりますか?

 提出 #18452990 (AC)

11分ちょっとで提出している。こうだったらこうだな、こうだったらああだなと考えながらとりあえず書き出してみてそれをそのまま提出した。

 B 問題 log

考えたこと。

  • 長さによらずコストが同じであるし、切れ端を捨ててもいいのだから、とりあえず長い方から買えば良い。
  • そしてもちろん、長い丸太から切り出して買うのを節約する丸太は、短い方から順に揃える。
  • n がいくつのとき、何本分の節約ができるかが問題。
    • 順番に書き出してみれば、長さ1を1本分節約するのに1本の購入が必要。(n=2)
    • そこからもう1本節約するには長さ2を1本用意しなければいけないので、追加で2本の購入が必要。(n=2+3=5)

節約する本数 k から n (の下限)を求める式が n ≧ Σ(k+1) = k+k*(k+1)/2 だということはすぐにわかったけど、n が与えられたときに k の最大がいくつになるのかを求めるのに、sqrt を使ってずっと考えていた。B 問題に取りかかってから最初の提出まで 46 分。

 提出 #18463725 (AC)

n の制約上限は 10^{18} であり、(10**18).bit_length は 60。なんだ探索すればいいじゃないと気がついたらもう問題は残っていなかった。

 C 問題 Large RPS Tournament

RPS って Rock, Paper, Scissors なんだな、たぶん。本番中はよく考えなかったけど。

k の上限は高々 100 ではあるけれど、2^k 通りの勝敗を考えるには大きすぎる数だ。まあ頭の中で考える分にはあまり関係がないので、トーナメントをシミュレーションして、その際に文字列 s のどの部分を参照するのかを確かめていた。優勝者の手、準優勝者の手、準々優勝者の手……がどこからやってくるのか、逆方向のシミュレーションもした。

 提出 #18467915 (AC)

最初の提出まで 30 分。C 問題という段階で解けなくてもともとなので、あせる理由はどこにもない。

 D 問題 く

残り時間は 30 分だったけど考えるだけ考えた。

  • 移動方法は3通り。軸となる2つの石を選べば決まる。
  • 石の配置は単位正方形を基準にして分類できる。すなわち、ある一角(たとえば左上)の座標と、くの字の折れ曲がり部分の位置(左上、右上、左下、右下)の組み合わせで決まる。
  • さて最小の移動回数は?

四角形の座標移動をまず考えた。

  • 水平方向、垂直方向に1移動するには2手かかって、くの字の向きが変わる。
  • 水平垂直同時に1ずつ移動するには3手かかって、くの字の向きはそのまま。

ここまで考えたが、この安定した移動に入る前と出るときに何手かかるのか数え切れなかった。B 問題のことを思い出して探索すればいいじゃない、ということには気がついたが、その探索がどういう形になるのかおぼろにも想像ができなかった。

というわけで D 問題はひとつの提出も用意できないまま放置している。


あ、3通りじゃないや、5通りある。じゃあいろいろ変わってきちゃうね。

え? 7通りある? だから最初から最後まで機械に数えさせるべきなんだな。


2020年11月28日 (土) 作業の待ち時間に Firefox の 22 (古い!) を使って時間潰しや情報収集をしたのだけど、その動作の(ESR 52.9と比較した)キビキビ具合は感動ものだった。SSD とかいらない。サーバーと暗号化方式で合意できなくて閲覧を拒絶される割合が半分を超えていた。チラシの裏に HTTPS はいらないとの考えのもと、この日記は HTTP で転送されています。いらないもののために何を捨てるのか。

最終更新: 2021-01-05T18:27+0900

[COSMOS] システムドライブを SSD に移した。(SSD 初体験)

やっとである。2012年と2015年と2017年に SSD 化の思惑を書いてるけど(2012111220150812p01)、今や2020年の末である。500GBで6500円である。

2007年に買ったHDDが丸13年間もった。いや、実はもっていない。最近になって不良セクタが見つかって名前も知らないファイルがいくつかロストしたのだけど、ケーブルを抜き差しして問題はなかったことにしていた。それから、ちょくちょくプログラムが一時的に停止するような状況が続いていて、IO 待ちなのかなと。ディスクがお隠れになってるのかなと。ファイルバックアップが正常に終了することが珍しくなったし、3回ほど INTERNAL_POWER_ERROR を理由とする BSoD を見たりもした。検索するとグラフィックスドライバが悪いとか、HDDが壊れてるとかで生じると書いてあるが、ドライバの再インストールとチェックディスクは不良セクタが見つかったときにもう済ませてある。処置無しである。完全な破局が訪れる前の今を限られた猶予として動かねばならぬ。

以前書いたとおり、まずは Complete PC バックアップをシステムドライブが入っているのとは別の HDD にとった。バックアップは毎月やっていることなのだけど、直前にまたとろうとしたら罠があった。少し前にとあるボリュームの容量を拡張しようとして、それは HDD の末尾に配置されていて後ろに空き領域がなかったものだから、拡張するにはベーシックディスクからダイナミックディスクへの変換が必要だという。誘われるままに変換したのが罠だった。ベーシックディスク上のボリュームである C ドライブのバックアップをダイナミックディスク上のボリュームに保存することはできないらしい。ダイナミックディスクをベーシックディスクに戻すにはボリュームをすべて削除する必要があるらしい。罠である。よりによってこのタイミングで。

ともあれバックアップを保存した HDD とフォーマットもしていない新しい SSD だけを接続した状態で Windows のインストール DVD から起動した。インストールは選ばずにその他のオプションから Complete PC バックアップからの復元を選んだのだけど、警告された。復元するとディスクはフォーマットされすべてのデータが失われると。それでも実行するかと。困ったのは、どのディスクがフォーマットされるのか全く示されなかったこと。画面上にはどのバックアップから復元するかを選ばせるリストがあり、T ドライブを選択したのだけど、それをどこに復元するのか、どのディスクがフォーマットされるのか、選ばなかったし提示されなかった。考えてみれば10年以上前にプレスされた DVD が昨日買ってきた SSD のメーカーや型番を知っているはずがないし、フォーマットしていないからドライブレターの割り当てもないし、どういう識別情報が提示できたかわからなくはある、……ような気がしたが、EFI でブートドライブの優先順位を決めるときに型番が利用できるのだから、デバイスに刻まれた文字列が利用できるはずでは? なんにせよ、いちかばちかで実行したらちゃんと SSD に C ドライブ(と Y ドライブも含めていた)が復元されていた。

さっきから C とか Y とか T とか、その他にもドライブレターの割り当てはないけど特定のパスに接合されたボリュームがいくつか存在しているように、細かくパーティションを分けている。NTFS ではそういうことは一度もないんだけど、ファイルシステムが FAT32 だったときはファイルの全ロストが何度もあった。BSoD もしょっちゅうだったし、そこからのコンボが現実の恐怖だった。失われるのはパーティション単位だから、巻き添えを少なくするために分けている。マウスを使ったファイル移動の既定がボリュームをまたぐ場合に(名前の変更だけで済まないからか)コピーになったりするけど、それだけ。Shift キーを押すか後で削除するだけの手間。

アイコンや文字のサイズなどデスクトップの設定がリセットされていたり、復元された Y ドライブ(まさしく自分の設定(レジストリ)が保存されている場所)が壊れているからチェックディスクを実行しろとファイルシステムからの鬼のような催促がイベントビューアに記録されていたりしたけど他は何も変わらず。もちろんレスポンスは速い。M.2 スロットなんてしゃれたものは 2011 年発売の MSI 990FXA-GD80 には付いていないし NVMe にも対応しないので転送速度は SATA3(実効転送速度 600MB/s)に律速される。500 MB/s 台が出ていたので大変満足です。HDD だとシーケンシャルでも 80 MB/s いけばいいところ。

SSD を知らない OS (Windows Vista) を SSD にインストールしてどうなるかはよくわからない。買った SSD のメーカーであるサムスンのユーティリティに期待していたのだけど、Samsung Magician 6 は Windows 7 以降でないとインストールできないらしい。Magician 4 はインストールできたけど当然ながら最近の自社製 SSD を認識しないので役に立たない。デフラグのスケジュールからは外したけど、他は何も。Trim はどうする? TxBENCH のインストールはした。総容量の4分の1しか埋まっていないしデータディスクは別にあるからここから大きく増えることもない。空き容量に任せてどうとでもなるんじゃないかな(なったらいいな)。


2020年11月27日 (金) このところここ半年ほどとくらべてあまりおなかが減らないわりに食欲も減ってなくて、冬に向けて太る準備をしているな、という感じ。抜け目なく体重と体脂肪率の推移を注視していかねばならない、とそう思うのでした(思うだけ)。


2020年11月24日 (火)

最終更新: 2020-12-08T00:48+0900

[Ruby] 多重代入の難しさの一例。(Ruby 2.7 と Ruby 1.9 で確認)

4月に「多重代入は遅くて時々評価順が難しい」と書いたけど、さらに難しいケースを考えた。クイズです。

a = *0..5 #=> [0,1,2,3,4,5]
b = *0..5 #=> [0,1,2,3,4,5]
a[i=2] #=> 2
b[j=2] #=> 2

a[i+=1] = a[i] # a はどうなる?
b[j+=1],= b[j] # b はどうなる?

a #=> [0,1,2,3,4,5]
b #=> [0,1,2,2,4,5]

a の結果を確認してから予想してカンマを付けたら予想通りの結果になったので驚きはないけど、やっぱり普通の代入とは違うんだなあと、それが遅くなる理由かなあと、思いました。

ゴルファーしかこんなコードを書こうとはしない? その通り。


2020年11月23日 (月) KLX300 が日本で買えるようになるといいなあ。(アメリカ仕様で) 137 kg だって。DR も XR も WR も、そして KLX もなくなってるもんなあ。


2020年11月22日 (日)

最終更新: 2021-05-07T14:51+0900

[AtCoder] AtCoder Beginner Contest 184/C,D,E

 C 問題 Super Ryuma

超竜馬の移動ルールを読み解くのが難しすぎると思うんだ。数学の言葉が通じない人のことを考えてほしい。なんとか解読した結果は、マンハッタン距離が3までの菱形の中と傾きが ±1 の直線上を移動できる、だと思った。

 提出 #18323156 (AC)

これ以上ない可読性を誉めてほしい。可読性とはこういうことだ。(他人が言う、ただの手癖レベルの)可読性なんぞいらない(どうして自分が書いたコードを、あなたにとって読みやすく自分にとってはそうではないように書き直さなければいけないのですか?)。この提出の可読性も認めてもらわなくて全然構わない。

 提出 #18373736 (WA×1)

先の AC 提出と全く同じ内容だが after_contest_01.txt という入力だけ WA になった。テストケースが弱かったので追加されたらしいのだが、みごとそれに甘えた嘘解答だったことが明らかになったということ。

 提出 #18374012 (AC)

after_contest_01.txt を通して本当の AC。可読性は維持している。

もちろん誇大表現は話半分に受け取らなければいけない。数学の言葉が通じない人向けに日本語で移動ルールを書けば曖昧さが入り込む余地が大きくなる。同じように、定義式を見て理解できることに日本語のラベルを付けたところで、ラベルの妥当性には疑問の余地がある。可読性(ラベル)は誰のためのものか。正確な理解ができない人間のためではない。時間がなくて式を読む時間を省略したい人に向けた補助である。時間があれば定義式を読むべきだし、時間がなくても即座に読み解ければそれに越したことがない。

異なる可読性もあると思う。読者を惑わせる無駄や回り道、曖昧さがなく目的に直結する、論理的で考え抜かれたシンプルなコードだ。そちらは追求していきたい。考え抜かれた結晶を、目で字をなぞっただけで読み解けるはずがない。読みやすさとは密度の薄さのことではない。一行を読むのにかける時間を変えればいいだけのこと。薄い内容をいっぱい読むだけ読んでも理解ができていなければ意味がない。理解するには知識と考える頭が必要だ。その時の対象はごく小さく限られている方が集中できて良い、というのが自分の考えであり性質。読むときも書くときもそちらを追求していきたい。

 D 問題 increment of coins

期待値? 定義しかわかりません。試行回数が不定? 一瞬で放り投げかけたが踏みとどまった。

A, B, C 3つも変数があると頭がパニックなので A*10000+B*100+C と1変数にエンコードしてみたらやや落ち着いた。試行を繰り返す遷移を書いて計算して足し合わせたら答えになった。求めたのではなく「なった」のである。

ただし += とすべき確率を = で上書きしていたためになぜかサンプル4だけ答えが合わなかった。「なぜか」はサンプル1から3の答えが合ったことに対する疑問。これのデバッグに30分ちかく溶かした。

 提出 #18339328 (AC / 867 ms)

同じ Ruby で 300 ms 台の提出があるのと比べると 867 ms はかなり遅い。しかしもう考えたくない。

 E 問題 Third Avenue

10分しか残っていなかったのでコンテスト時間中の提出は適わなかった。ただやるだけだと思ったけど、それを手早く正確にやる能力がなかった。多少の時間の余裕があってもダメだったろう。

 提出 #18348009 (WA×1 / TLE×3)

TLE はいいけど WA はいただけない。今日は寝る。

 提出 #18371108 (AC / 2995 ms)

はい、やるだけでした(だがそれができなかった)。TLE まであと 5 ms なのは改善の余地があるだろう。

WA の原因は再訪防止のマーキングを、行こうとするときにチェックを付けるか、着いたときにチェックを付けるかの差だと思う。効率を優先して先走ると間違える。過去に何度も同じやらかしをしているので多分そうだと思う(今ここでよく考えないから次もまた同じミスをするんじゃないか?)。

 提出 #18397451 (AC / 1883 ms)

30% あまり速くなったがあまり本質的ではない改善要因(予想)が5つあるだけである。

  • 再訪防止フラグ(配列 T)のインデックスを誤って使用していた。

    問題として与えられるグリッド文字列に番兵として1行1列を加えていたのだけど、再訪防止フラグはそうではなかった。それにもかかわらず番兵込みのインデックスを使って(予防的な)再訪チェックをしていた。

    訪れるべき所を訪れ損なっていなかったのは運が良かっただけだし、訪れなくてもいいところを無駄に再訪していたと思われる。

  • 壁のあるマスにも再訪防止フラグをセットするようにして、予防的な再訪チェックに引っかかるようにした。
  • テレポーターの前処理をする際に正規表現を引数にした String#index を使っていたのだけど、パターンを /[Sa-z]/ から /[a-z]+/ にした。

    S の有無は関係なくて、連続するテレポーターをひとまとめに処理対象にした。

    String#each_char で1文字ずつ文字種をテストするのにくらべて正規表現という仰々しい道具を持ち出した String#index が有利になる条件は、テレポーターが疎に配置されていて処理対象外の文字を大きくスキップできる場合だと思う。

    逆に言えば、テレポーターが密に配置されていて index が1ずつしか増加しないとき、ただの文字種比較とパターンマッチングを伴うメソッド呼び出しの1回あたりのコスト差が顕在化する。

    index メソッドの呼び出し回数を減らすためのパターン変更。

  • 上下左右の移動先を処理する4要素の配列のイテレーションを展開してべた書きした。
  • 使用済みのテレポーターの処理に関して、空の配列を concat しないように事前にチェックするようにした。結果が同じでも、記述が煩わしくても、パフォーマンスのためには事前にチェックする方が良い。

    インクルードガードにも内部インクルードガードと冗長インクルードガードの2種類があって、冗長でもインクルードそのものをスキップするように書けばファイルを開いて閉じる手間が省略できてコンパイル時間が短くなる。最新のコンパイラ、プリプロセッサがそんな愚直なやり方をしていると信じる理由はないけども、原理的にはそういう差がある。

 提出 #18446644 (AC / 1490 ms)

もう 20 % ほど速くなった。

  • 添字を使った文字列へのアクセスと配列へのアクセスは倍ちょっと速さが違う(Ruby 2.7)。添字の大きさは関係ないみたい。ちなみに Ruby 1.9 は 10 倍違った。
  • 再訪防止フラグを早めに立てるようにしたからキューが長くなりにくいと思う。予防的なチェックが本式のチェックになったからメインループでのチェックも不要になった。
  • 前処理に正規表現を使うのをやめて1文字ずつ細かく準備できるようになったから、再訪防止フラグを利用してメインループの when 節が1つ分減った。

それから、1つだけの WA の原因はよくわからなくなった。少なくとも再訪防止フラグをセットするタイミングが必ずしも理由になるわけではない(今回の提出では移動しようとする先のフラグを立てるようにしたから)。何かをミスればそれを咎めるテストケースがちゃんと用意されているというだけ。別の提出では別のケースが1つだけ WA になった。