3が1より小さいなら、3は10より大きい」。命題(P ⇒ Q の Q)があからさまに偽だからこの偽の命題を成り立たせる(P 以外の)隠れた条件は何か、という風に逆転した論理を自動的に考えてしまうのだと思う(生存戦略。ヒトは全知全能の神ではないが、無知の知ぐらいはある)。そうなるともう何もわからない……。■種明かしを読めば Ruby で空配列に対するクエリ
[].all?
が(どんなブロックを与えても与えなくても) true を返すのと同じだと理解できる。■これには疑問>「最後の「3が偶数なら、4は奇数である」が正解多数だから1の"P が偽ならば、Q の真偽にかかわらず「P ならば Q」が真である"は理解してる人が多い」。 偶奇って正負、陰陽、表裏、左右と同じでペアのそれぞれにアイデンティティがあるわけではないので、「3が奇数なら4は偶数だし、3が偶数なら4は奇数」というように納得して正解の選択肢を選ぶことができる。しかしこれはさっき書いた逆転した論理。自分のように偶奇の性質によってたまたま正解が選べただけの人がいるのでは?■■■@2021-06-23 今日読んでいた本『『詭弁論理学』(野崎 昭弘 (著) / 中公新書)』の 171、172 ページにちょうど書いてあった。「
『もし Q ならば、Pである。』と『P でない。』とは、どちらも正しい(ことがありうる――Q でないことが結論される)ので、矛盾とはいわないのである。『もし Q ならば、P である。』と『もし Q ならば、P でない。』とも、Q が起こりえない状況においては、『Q でない』ことが確認されるだけで、矛盾ではない。」
git checkout -b myBranch 本家/master
、git push -u myGitHubRepo myBranch
、git rebase 本家/master [myBranch]
というフローで作業をするために、「自分のではないリモートリポジトリへのプッシュをできなくする」「
新しく作成したブランチが自動的に設定する、分岐元との繋がりを断つ(--no-track を既定値にする)」という下準備をローカルリポジトリで行っていた。そもそも「
(クローンしたなら)リモート名 origin を削除する。余計な自動化も自分が管理しない名前もない方がまし」という考えによってリモート名 origin が存在しなかった。■だって origin ってリポジトリ名なの? ブランチ名なの? 本家なの? フォークなの? そういう曖昧なものの上で作業をしたくない。ましてそれ(origin)が他人(git)のお膳立てなら、助けではなく余分な複雑さを持ち込むようにしか思えない。定型のタイプの繰り返しに倦んできた頃に提案してくれたなら考えないこともない……かな? それでもやっぱり自分は pull は使わないので(許容できるのは checkout や add までであって、自動で merge/rebase は乱暴だ)、origin もいらないんだよな(本家リポジトリにはその代わりにわかりやすい名前を付けます。「
ブランチ名とひと目で区別できるように、リモート名は @ を付けたり大文字にしたりしようかな」)。■自分にとって3つのリポジトリの関係は「本家―ローカル―フォーク」として捉えられている。でもひょっとしたら「本家―フォーク―ローカル」の想定もあるのかもな、と考えてみた次第。でも自分で GitHub にフォークリポジトリを持たなくても「本家―ローカル(フォーク)」の2者間でもフォークは成り立つので、中心に GitHub 上のフォークリポジトリを置くのは、GitHub の中の人の立場としてならともかく、個人としては順序が違うと思う。メンタルモデルはひとつで十分だ。そのとき GitHub 上のフォークリポジトリは3番目に位置するオプショナルな存在となる(だから意識しなければこれを忘れる>「
フォークする。プルリクエストを出すためには GitHub 上でフォークしたという事実が大事」 新規作成した空のリポジトリにプッシュしても PR は出せないのである)。■しかし GitHub のアップデートによって今後は、GitHub と origin を必須の前提として作業フローからリモートの区別・存在感を消すのがある種最適な選択になるのかもね。本家とフォークの2つのリモート名を使い分ける必要がなくなるのなら、単純化がなされるのなら、割り切りによる制約がむしろメリットと感じられる人もいるだろう。さもなければ無駄に複雑化して面倒なことをしているなと自分は思います。
最終更新: 2021-04-30T21:11+0900
「10分間3問早解き」回だったわけなので4問目(D 問題)は時間中に解けなかった。90 分使っても解けなかった。辺がないケースで TLE が避けられなかった。
AC のきっかけはこのツイート。
chokudai(高橋 直大)ナス@chokudai
D問題、非連結ですって言うだけでDiff400くらい落ちそう
chokudai(高橋 直大)ナス@chokudai
非連結ですって言っても落ちないわ(サンプルにあるし)
連結で出題しないと400落ちなさそう。
「連結で出題しないと落ちない
」がよくわからないけど、ともかく、非連結なら問題を分割できるじゃん、と気がつきました。ツイートを読んで初めて気がつきました。
サンプル4つのうち2つが辺がゼロのケースだったんだけど、極端すぎてそれが全体としては非連結なグラフであること、個々の頂点としては最も簡単な連結成分を構成している、ということがわかりませんでした。そんなことってある?
テストケースが公開されていないので、提出前のテストには一直線の木を使っていた。連結成分の数を増やしても、辺の数を増やしても、探索を助ける制約が増えるだけだと思ったので。
しかしまだ TLE。どういう木が嫌か考えると、この提出は次のような入力に弱い。
だけど次のように番号の付け方を変えただけで問題が問題でなくなる。
たぶん頂点を次数でソートしてから DFS をすれば緩和されたと思う(が、AC 提出では違う方法(先読み)をとった)。
ソートするにせよ先読みするにせよ、2番目の問題に対処するには非連結なグラフを連結成分に分割する必要があったが、それをしないまま DFS の処理量を削減する方法を考えていた、というのが失敗に終わったコンテスト中の時間の使い方だった。
DFS の処理順を次数の降順にしたら悪くなりにくいのか、343 ms からタイムが大いに改善した。このムラが DFS の沼であり抜け出せない楽しみなんだよなあ>20201101p02、20201107p01.05。
最終更新: 2021-06-11T11:27+0900
以前書いた。「最初に右辺を評価して、それから左辺の評価と代入を左から順番に実行していく感じかな? 右辺の一時記憶が必要? 多重代入は遅くて時々評価順が難しい、というのが現在の評価。」「クイズです。a の結果を確認してから予想してカンマを付けたら予想通りの結果になったので驚きはないけど、やっぱり普通の代入とは違うんだなあ」
そしてこの PR が多重代入について>Evaluate multiple assignment left hand side before right hand side by jeremyevans · Pull Request #4390 · ruby/ruby マージされている。
3.1.0 から変わりそう? 評価順が変わってパフォーマンスがさらにちょっと遅くなる? 新しい評価順っていうのが、
従来は2が最初にあって、1と3がインターリーブされていた。……ということが PR の概要欄と NEWS の修正に書いてある。
パフォーマンス劣化の理由は左辺の評価結果を一時的に蓄える必要があるからか?
いやあ、あっさり変えるし変えられるもんなんだなあ。まあたぶん、Ruby ユーザーの 1 % も変化に気がつかないだろうとは思う。
非効率だしバグらせやすいし、作り込む価値がないと言っている?
自分はもうこの仕様について(穴にはまった実体験から)知っているので、常に穴を意識して書くし、逆に評価順を利用することもあるけど、これまで幸運にも意識せずに来られた大多数のユーザーが、将来的潜在的には驚きとともに多重代入の評価順の詳細を理解させられるんだろうな、ということを考えると、「作り込む価値はある。ただしうまく実装できる限りにおいては」という評価が妥当かなと思う。
最終更新: 2021-06-08T15:01+0900
昨日あった ABC。D 問題は覆面算。たまたま何か月か前に「FDCAJH × IBCFEH = FBAECIIJEGIH」というのを解く機会があったのだけど、時間制限がないせいで雑に総当たりをして済ませてしまっていた。
本番中は TLE で終わってしまった。E 問題を 15 分で片付けて戻ってきたけど、ついに通せなかった。
制限時間が大盤振る舞いの5秒なんだよね。
桁を1つ2つ減らすだけで時間がだいぶ違うだろうという予測はできたけど、減らし方がわからなかった。なんといっても目の前に文字で書かれた式があるわけではなく、色々なケースが入力されるわけなので。
TODO: Array#all? の中のテストは l<=r
より l==r||l+1==r
の方が厳しくて良い。
TODO: 和の先頭の桁が1だとすぐにわかる場合がある。
TODO: 列挙してから弾くより列挙しない方がいい。(確定桁が1つあったとして、未確定桁(=文字種-1)の順列の数だけ弾くのは手間だから)
TODO: ループの中の処理がシンプルになるように入念に事前準備をした方がいい。
現在 Ruby での AC 提出は 20。実行時間が 109 ms から 4845 ms までと幅広い。中央値は3秒台です。
たとえば(4桁 ms では最も速い)約 1.6 秒のこの提出>#21688714
先頭桁が0のケースを弾くと同時に、末尾の桁が一致するかどうかだけ特別にチェックしている。一致しないケースでは文字式の全体を数値化する無駄がスキップできる。このひと手間が効果的なのだと思う。
それと、全くの想定外だったのだけど、文字が 11 種類以上使われている式が入力されるケースがあったのだろうか(上の 1.6 秒の提出がチェックして UNSOLVABLE を出力している)。AtCoder の問題は入力や条件がきれいに整理されていて枝葉の手間が省けるように作られているだろう、という甘えがあるのは否めない。
3つある3桁 ms の提出が何をやっているのかは、さっぱりわかりません。
4つの TODO を意識して書いたけど、妥協した部分もある。
とはいえ、これを深さ優先探索で妥協なく書き換えただけで2桁 ms になる? そう、Ruby で現在最速の提出は 71 ms になっている。
根本的なところで、列挙してから弾くか、可能性のある組み合わせだけを列挙するかという違いがあるのかな。そっち方面で書こうとしたときは、ある桁を見たときに未確定文字が0なのか、1個あるのか2個か3個か、未確定文字があるのはどの項か、繰り上がりはあるのか、ということを考えるのが面倒くさくなって(=脳のキャパシティをオーバーして)、書けなかったんだよね。
書けなかったのをがんばって書いた。時間は申し分ないけども1つの WA。たぶん答えがないケースだと思うんだけど……。
WA の原因は非ゼロチェックが1つ抜けていたこと。それと、想定外だと書いた「文字が 11 種類以上使われているケース」はサンプル4がそうだった。コピペするだけで全然読んでいない。
雑に総当たりしていたのを反省して(TLE は嫌だ!)、数か月ぶりに書き直した。提出 #21743445 をベースにして、掛け算に対応させた。prd の計算が難しかったのですよ。ありえたかもしれないもうひとつの筆算のかたち。すっごく縦長になるけども。
A = 'FDCAJH'.bytes.to_a # to_a is for Ruby 1.8/1.9 B = 'IBCFEH'.bytes.to_a P = 'FBAECIIJEGIH'.bytes.to_a C2D = [nil]*91 D2C = [nil]*10 NZ = [-1]*91; NZ[A[0]] = NZ[B[0]] = NZ[P[0]] = 0 F = lambda{|i,carry,aa,bb,zz| next carry<1 if i<-P.size a = (c = A[i]) ? C2D[c] : 0 b = (c = B[i]) ? C2D[c] : 0 if a next D2C.each_with_index.any?{|e,d| next if e || d==NZ[c] C2D[c],D2C[d] = d,c next F[i,carry,aa,bb,zz] || C2D[c] = D2C[d] = nil } unless b prd = a*bb+b*aa+a*b*zz+carry if p = C2D[c=P[i]] next p==prd%10 && F[i-1,prd/10,a*zz+aa,b*zz+bb,zz*10] else p = prd%10 next if D2C[p] || p==NZ[c] C2D[c],D2C[p] = p,c next F[i-1,prd/10,a*zz+aa,b*zz+bb,zz*10] || C2D[c] = D2C[p] = nil end } raise unless F[-1,0,0,0,1] puts [A,B,P].map{|a|'%*d'%[P.size,a.inject(0){|b,c| b*10+C2D[c] }]}