/ 最近 .rdf 追記 設定 本棚

脳log[2023-10-28~]



2023年10月28日 (土) [AtCoder] 今日はパナソニックグループ プログラミングコンテスト2023(AtCoder Beginner Contest 326)があった。自分のすべての提出。では ABCDE のふりかえりと F の精進を。F 問題を通すには時間が 15 分足りなかった。D 問題に 50 分かけていなければと悔いが残る結果。■A 問題「2UP3DOWN」。慎重に X と Y の大小を比較してから階段を使うかどうかを判断した。■B 問題「326-like Numbers」。ちょっと前に 321-like Number というものが出てきた。今日の 326 は3桁であることが明白な定義なので易しかったと思う。■C 問題「Peak」。尺取りです。■D 問題「ABC Puzzle」。最大で 5×5 のグリッドだけど、(5*4*3)^5 大なり7億なので愚直総当たりが許されるというわけではない。だけどまあ、ちょっとだけ工夫すれば総当たりに近いことはできる。グリッドが条件に違反していないかを判定する関数を書いてから1行ずつ文字を埋めて判定を繰り返した。実装問題でまんまと時間を使わされた。下手かよ。■E 問題「Revenge of "The Salary of AtCoder Inc."」。名前でにおわせているけど給料に関する問題を解いたことがある。調べたら「AtCoder社の給料」だった。だけどそんなことは今日の問題を解くのには関係がない。答えが合わないからデバッグのためにまずは小数で答えを出すことにした。たぶんすごく簡単な式で答えが出そうな気がするけど、頭がないので手続きを踏んで答えを足し合わせた。今ここにいる確率というものを1つ変数に記録しておいて、A 数列を順番に見ていった。A[i]×(今ここにいる確率) がまず答えの一部。そしてまだ見ていない A 数列の要素にとっての今ここにいる確率というものは、いま今ここにいる確率の N 分の1だけ増える。■F 問題「Robot Rotation」。こういう設定の問題知ってるよ。成分を上下成分と左右成分に分けるやつ。DP をするかと制約を見たら N の上限が 80 と意外に小さい。成分に分けるとそれぞれ 40 だ。2 の 40 乗はべらぼうな数なので各要素をプラスに利用するかマイナスに利用するかを総当たりはできないけど、半分ならどうか。2 の 20 乗はおよそ 100 万でちょうどいいサイズ。100 万と 100 万の組み合わせを総当たりはできないけど、足して X,Y になる相方が存在するかの判定は定数(っぽい)時間で行える。ここまで考える要素はなかった。しかし実装するのに十分な時間もなかった。残念。■出ました。コンテスト成績証。青パフォで上がりはしたけど上がり幅が足りない。F 問題解けてたよ!■D 問題。自分のこの提出 #47031545 の判定関数 OK だけど、前半と後半が繋がっていないので前半の判定結果が捨てられている。嘘判定なんだけど、行方向に関しては制約に違反しないように F 関数の方で配置しているのでセーフだった。怪我の功名。どちらかの関数で行と列の扱いが逆なら間違いだった。


2023年10月27日 (金) [COSMOS] データ用 HDD (2 TB) を 6 TB のハードディスクと入れ替え。ふと見たら残りが 20 GB を切っていたので。2 TB ないくらいのデータのコピーに6時間以上かかって、ケースが閉められないまま一日仕事だったんだけど(この日記を書いている 28 日土曜日が仕事の日だったという意味ではなくてですね、自分が寝る前には終わらなかったという意味)、計算してみれば HDD の読み書き性能が 100 MBps だとして時間当たりおよそ 350 GB なので、10 時間かからなくて良かったね、といったところ。このあと新入りの 2 TB HDD を加えた(一群でひとつの)仮想的なバックアップディスクに新しくバックアップを作るので、また同じかそれ以上の時間がかかる見込み。どうでもいいけどカテゴリ名は PC ケース(CoolerMaster COSMOS (RC-1000-KSN1-GP))から。まだ使っている。気をつけないともろくなったプラスチックパーツが砕けたりする(目に付かないところなのでセーフ)。土曜日の日記は ABC のために空けています。


2023年10月21日 (土) [AtCoder] 今日はキーエンスプログラミングコンテスト2023秋(AtCoder Beginner Contest 325)があった。自分のすべての提出。結果は知らないよ。今日の日記には DEF の精進が含まれてるよ。要するにそういうことだよ。■A 問題「Takahashi san」。名前部分をちょん切って 'san' をくっつけます。■B 問題「World Meeting」。いきなり難しいなと思ったけど、入力がすべて整数なので扱う時刻は正時(セイジでなぜか変換できないと思ったらショウジって読むらしい)のみの 24 通りだけだった。なら時間枠に参加人数を加算していくのみ。■C 問題「Sensors」。UnionFind でやった。そうでないなら DFS でやるのがいいと思う。BFS は難しい。友達の友達は友達という関係には再帰構造があるので。センサーがないマス(.)については頂点を1つ追加しておいてそれとグループを作るようにした。そうしたら最後にグループ数から -1 するだけでいい。■D 問題「Printing Machine」。時間内に解けなかったので精進だよ。時刻の幅が鬼門。10 の 18 乗まであるから飛び飛びの時刻を処理するしかない。情報を蓄えておいてあとからシミュレートする。最終的に AC になった提出では、プライオリティキューで現在印字待ちのアイテムについて印字処理のリミット(t+d)を管理し、また、最後に処理した時刻(t0)を記憶しておいた。そして処理開始時刻(t)でソートしたアイテムについてループを回した。区間の端を -1 したりする処理で間違えていた。■E 問題「Our clients, please wait a moment」。D 問題と心中したので E 問題は終了後に読んだ。AC まで 21 分だった。都市1から車で移動した場合の各都市までの所要時間を調べ、都市 N から電車で移動した場合の各都市までの所要時間を調べ、zip して足したものの最小値が答え。最短距離を求めるのに D 問題で使ったプライオリティキューをまた使ってダイクストラ法なのかなと思ったけど、完全グラフなので log を付けるより総当たりの方が良さそう。それは Cosmic Rays (20211031) の経験から。■F 問題「Sensor Optimization Dilemma」。なかなか方針のしっぽが掴めなかった。DP なのか二分探索なのか。制約の攻めどころはどこか、上限が 1000 の K だろうか、高々 100 でしかない N だろうか。結果的には DP だった。区間(D)についてループを回し、センサー1の使用回数に対してセンサー2の使用回数を最小化するような DP をした。NKK≦1億なので Ruby では1桁オーバーで通らないかと思われたけど、112 ms であっけなく通った。謎。■おかしいなあ。これでなんでコンテストは ABC の3完なんだろうなあ。たぶんだけど、今が 25 時をまわってることと関係がある気がするな、たぶんだけど。■AtCoder Problems によると DEF の難易度が順番に 水緑青 だった。D と E が逆転している。そうだろうなあ。もっとも、自分は水 diff は解けていないといけないので、解けたのが ABC でも ABCE でも不出来なのは同じ。点取りムーブに興味はない(負け惜しみ言ってら)。まあまあ、長い目で見て AtCoder さんの評価が自分に追いついてくるのを待っていてあげようじゃありませんか。


2023年10月17日 (火) ここ1、2週間 Cyberpunk 2077 を猿のようにプレイしていたせいで精進が滞っていたが、やっと一段落した。最初は PS4 パッケージ版 (ver.1.6) を 70 時間ほどプレイした。CERO Z なのでパッケージ版なのは決まっているが(「俺はクレカがインフラだとも唯一の(そして真っ当な?)成人認証手段だとも思わんよ」)、PS5 版のパッケージはないみたい。無料アップデートができそうだと確認して PS4 版を買ったのだけど、無料アップデートにもクレジットカードの登録が要求された。なんだそれ。パッチアップデートとは扱いが違うんか。それで 10 回も 20 回もエラー終了する PS4 版を PS5 でプレイしていた。そのうちに DLC に先だって ver.2.0 が PS5 向けに配信されて、ゲームのクエスト以外の部分、キャラクタービルドや装備品の扱いがリメイクと言っていいくらい、パラメータではなくシステムから変わっていたので、データの引き継ぎもできたけど推奨されている通りに 70 時間のデータを捨ててイチからまた開始したのだった。Cyberpunk 2077 のために節を曲げたのだ。最初に選んだ生まれはコーポで、2度目はストリート。1度目は問答無用でターゲットを殺したクエストが、2度目では相手の事情を汲んで姿を消すことを勧めた結果戦闘が起こらなかったりした。逆にコーポの生まれでないと立ち入れない裏事情もあったり? 難易度はハードで始めて途中でベリーハードに切り替えた。敵の移動にエイムが引っぱられるのが気持ち悪くて設定でスナップを切ってアシストも弱にしたがまだ引っぱられてるぽい? そこはまあヒャッハーの気持ち良さとの兼ね合いでアシストを切るまではせず。愛銃は1度目も2度目もサラトガ FENRIR。単発火力が低いけど連射が早くて狙いが甘くても安心のサブマシンガン。炎上確率が高い銃だったけどアップデートで感電確率に変わっていた。1対1での制圧能力の高さは変わらず。サラトガが着火能力を失ったために用意した第2の銃がリバティ SERAPH。14 発装弾のピストル。ヒットするたびに敵が浄化の炎に包まれる確率が高まるという。適度な炎上確率でロシアンルーレットの楽しみがある。射程は FENRIR と同じく近中距離だけどやや長めだからスナイパーライフルの出番を食っていた。確実なヘッドショットが求められるのが苦手。それに遠距離ならひと目見るだけで相手をロックオンできるクイックハックが強い。エイムが不要という点でショットガンは魅力的だしターミネーターごっこが楽しそうだけど、ver.2.0 では完全に近接武器としての立ち回りとビルドが求められていて使わず。終盤に手に入れたコパーヘッド PSALM 11:6 が第3の銃。これもそうなんだけど、アイコニック武器は設計図として入手するものがいくつもあるので、注意しないとクラフトを忘れて死蔵してしまうことになる。わりと終盤まで気がつかなかった。連射能力はサブマシンガンに譲るが単発火力が高めのアサルトライフル。火力高し。着火能力あり。ピストルでは手に負えなくなったときに頼りになるやつ。スマート武器はシューターとしての興を削ぐ気がして使わず。テック武器はチャージによる発砲までのラグがどうにも慣れなくて使わず。チャージ完了による自動発砲は止められるんだけど、そこに割り振るパークポイントが不足していた。パワー系のピストルとサブマシンガンとアサルトライフルを使っていた。パワー系だけど跳弾するところは見たことがない。どれもサプレッサーが付けられるのがいい。終盤は火力が下がるのを嫌ってピストルにしか付けていなかったけど、そこは使い分け。実は一番の主力はクイックハック。ハックとマイニングで経験値が稼げるネットランナーが上限の 60 レベルに到達した最初のスキルで、いまのところこれだけ。他はヘッドハンターとシノビとエンジニアが 50 レベル前後でソロが 25 レベルくらい。サイバーサイコシスで同士討ちとか強制自爆とか楽しいのが揃ってるけど、楽しくて実用性も高くて他に類がないのが化学汚染だったと思う。一番使った。やや低めで長めの継続ダメージと付近の敵への伝染性が特徴だけど、とっておきはエピック、レジェンダリクラスで付与される爆発性。ダメージ継続中に着火したり、炎上中に感染させたりすると爆発するようになる。毒の継続ダメージは終了してしまうけど、継続ダメージを瞬間火力に変換できると思うと役割があるし、何より楽しい。リバティ SERAPH の適度に低い着火確率で、まだかなまだかなと銃弾を撃ち込むのが。化学汚染の伝染性の特徴。A と B の敵が近くにいるときに A に化学汚染を仕掛けると、2秒か3秒のアップロード時間の後に継続ダメージが発生する。そのとき B が A の近くにいると B へのアップロードが A への継続ダメージと同時に始まる。それで B の継続ダメージが発生したタイミングでまだ A が傍にいると A へのアップロードが始まるのが特徴。無限ではないけど何度も反復して伝染するし、上限はあるけど継続ダメージも上乗せされる。時間あたりのダメージ量ではオーバーヒートによる炎上の継続ダメージの方が大きいけど、伝染性と持続性と瞬間火力への変換可能性で化学汚染に独自の使い道がある。もうひとつゲームチェンジャーなのが周囲への伝染が最初のアップロードと同時に始まるというサイバーデッキの存在。それを装備してると化学汚染の伝染が反復しなくなって継続ダメージの総量には不満が出るかもしれないけど、たとえば A と B と C が密集してるときに3人の誰かに化学汚染を仕掛けると、同時に3人へのアップロードが始まって、同時に3つの人間爆弾ができあがるわけで、1人に着火するとみんな吹っ飛ぶ。こんなに楽しい遊びがありますか。ベリーハードだと1度の爆発では死ななかったりするんだけど、すでに炎上してるなら2度目の化学汚染のアップロードが完了したタイミングでまた吹っ飛ぶ。楽しいし対集団に対応できる頼もしいやつ。そういう使い方なので継続ダメージが低いけど他のスペックが同じで消費 RAM が低いエピック級をレジェンダリ級に優先して使っていた。いつでも何度でも使える方が大事。パークポイントだけど、フィニッシャーだとかデッドアイだとかオーバークロックだとか、そういうモードが切り替わったりキー入力が要求されたりする特殊能力には割り振らなかった。サイバーウェア装備上限を上げるエッジランナーだけ。SEKIRO のプレイスタイル(「弾き一辺倒で押し切りたい」)もそうなんだけど、器用にあれこれできない。オプションが増えるとすべてが中途半端になる。スタミナ消費軽減などの地味なパッシブ能力に集中して割り振っていた。敵を気持ちよく殺してるときに突然画面が黄色っぽくなって悪魔的な笑い声が聞こえてくることがあるんだけど、消去法で判断するとどうやらあれがエッジランナーの副作用であるフューリーが発動しているところらしい。意味がわからなくてすっごくビビッたんだから。NCPD アイコンはマップのカスタムフィルタでチェックを入れるまで表示されない。他のクエストを全部消化するまでは偶然の遭遇に頼って気が向いたときに消化していたし、実は決まった場所で発生しているということも知らなかった。ランダム発生なのかと思っていた。それでアイコンを表示してみてトロフィー条件にもなってるのにその数の多さに絶望しかけたけど、全然苦にせず消化していけた。車の運転が楽しかったからアイコンからアイコンへの移動が苦にならなかったというのが理由。ちょっとくらい距離があってもドライブ気分で移動していた。愛車はタダで手に入れた TURBO-R V-TECH。カリバーンの入手クエストのアイコンが ver.2.0 ではマップに出なかったし、洞窟に行ってみても手に入らなかった。ひょっとしたら別のクエスト中に廃車にしてしまっていたとかそういう影響があるんだろうか。1度目は思いとどまらせたパナムの復讐だったけど、2度目はアイコニック武器欲しさに敵陣(これがカリバーンの洞窟?)に乗り込んでいったのだった。最初はジャッキーのバイクが運転しやすくてずっと乗っていたけど、慣れると車の運転がおもしろい。シリーズで一番長くプレイしたグランツーリスモ2を思い出す操作感。コントローラーでの運転がとってもピーキーで、ほとんどの操作が急ハンドルフルアクセルフルブレーキになるときに、ハイパワーの FR 車にオーバーステアを出させない操作が求められる。ボタンを押すテンポで PWM 制御をするんですよ。砂漠を横切る道路を高速で走ってるとふわふわと接地感がなくなってきてお尻を振り出す挙動にも覚えがある。最高速度が下がってもウイングで押さえつけないと。車の壊れ方にバリエーションと段階があって、ドアがなくなっているから乗り込むときにサイドシル付近の可動部がよく見えたりする。見えないところで動いていた。これって車ゲームじゃないよね? 運転席に首振り人形が置いてあるよ。男主人公だとジュディといい雰囲気にならなくて、女主人公だとパナムといい雰囲気にならないのは、意外に感じたけどそういうものかもしれないね。ジュディはレズであってバイではないし、ケリーはゲイであってバイではない。相手が主人公だからってオール OK ではない。書いていて自分で反発を覚えたので補足するんだけど、キャラをカテゴリにあてはめて理解したいわけではなくて、自分にとってありえない選択があるように、そのときのそのキャラにとってもありえない選択があったんだろうなということ。だってふられた理由をそうやって説明したいじゃない。あとはね、ローグおばあちゃんがかっこよくて、ジョニー坊やのズッ友に脱力させられた。お前体をのっとって勝手にタトゥーを彫ってると思ったら、それかよ。J+V4EVAH じゃねーんだよ。服装はだいたいこんな()。(70+)140 時間くらいでエンディングを4種類見た。DLC はまだ。今は PlayStation Store のまったく参考にならないわずかな情報にもかかわらず購入を決めた Cult of the Lamb が当たりだったので睡眠時間を削ってプレイしている。精進はどこ?■Cult of the Lamb だけど、直や植や反の字形が中華フォントなのはローカライズしっかりしてほしい。子供がそういうのに触れると令やしめすへんと同じようにちょっと違うけど同じものだと学んでしまうんだよ。実際それは大きな括りでは間違いではないのかもしれないけど、自分の感覚には合わないのでできればそうはなってほしくない。そしてこれはクライアント(PC)の問題だけど、自分の PC(Vista) で publish.obsidian.md を読んでも普通の明朝体だけど、Windows 10 で読むと同じ中華フォント字形に遭遇する。Android にもある現象らしいし、そもそもは Unicode の問題。Emoji みたいな完全にフォントごとのグリフと個人の偏見に基づいた意味しか持ち得ないうんこばっかり追加してる場合じゃないよね。たとえばよく見る泣き顔の絵文字って最高にいらっとさせる効果を持ってると自分は思うんだけど、すべての泣き顔がそうだというわけではない。いま見えている泣き顔の絵文字がそうだというだけだ。どういうつもりであの絵文字を使ってるのか若干興味がある。煽りが過半数だったらおもしろい。要するに、疑いながらではあるが第一印象として、自分はそのように受け取っているということ。


2023年10月16日 (月) [AtCoder] 精進。昨日あった ARC167-D「Good Permutation」(黄 diff)。とっつきは悪くないんだよね。数列がいくつかの巡回グループに分かれるときに、グループ間で要素をスワップすることを繰り返して全体を1つのグループにすればいい。操作回数を最小化するのが第一なので同一グループ内でスワップはできない。難しいのは辞書順最小の順列を効率良く作成する手順。UnionFind でグループの最小値と末尾の位置を管理したうえで、数列を前から順に見ていって、今見ている要素より小さい値を持つ他所のグループとのあいだでスワップ&マージしていった。ところがそれだけでは辞書順最小にならないことがある。たとえば 2 1 4 3 という順列は前半後半の2グループに分かれていて、1回のスワップで達成できる辞書順最小は 2 3 4 1 なので、1 と 3 をスワップする必要がある。何をどう判断して 1 と 3 をスワップすることができるのか。さっきのルールでは 4 を見ているときに 1 を引っぱってくることになって良くない。グループの末尾の位置にあっては多少の妥協をして現在の要素より大きい値を引っぱってくることになっても他所のグループとスワップをしなければいけない。それで 1 を見ているときに 3 を引っぱってくることができる。そうした結果が本当に辞書順最小かというのは実はよくわからないところだけど……。■提出 #46663066 (TLE×18) のち 提出 #46665195 (AC / 772 ms)。アルゴリズム的な違いはない。スワップ候補というのは1度に2つだけ準備できていればいい。最小の要素を持つグループと、2番目に小さい要素を持つグループ。現在見ている要素と異なるグループが実際のスワップ対象になる。この2つの要素を配列の外に出して変数で参照するようにしたりして配列参照を減らしたら TLE が AC になった。■グループの管理とスワップ候補の管理を同時に行うために、UnionFind のルートの決め方をいつものようにサイズの大きい方を新しい代表にするのではなく、値が小さい方を新しい代表にしている。そうすると Find 関数での書き換え回数が増えてまずい場合があるのだけど、代表と最小要素を別々に管理するのは煩雑でミスが避けられない雰囲気だったのでそうしている。スワップ候補の列について。最初にソートして用意するんだけど、スワップ1回につき1つの候補が列から消えることになる。現在見ている要素の代表が消える場合もあり必ずしも先頭2要素のどちらかが消えるとは言えないし、Ruby には SortedSet がない。今から BIT を持ち出すのは大仰で気が進まないし、消す操作を配列に対して素直に行うと実行時間が足りないので、スワップ候補の先頭2要素についてだけ今もまだスワップ候補(グループの代表)のままであるかチェックをするようにして、結果的に削除操作を遅延させている。こういう部分であるとか、数列を先頭からひとなめするだけで辞書順最小を達成するだとかいう部分があるから、効率良くやるのがたいへんな問題だったと思う。スワップするためには最小の要素がどこにあるかを知る必要があって、それを追跡する逆引き配列を予め作成してスワップの際には同時に更新しもしている。たいへんだなあ。そのときそのときで全体を見て最適な選択ができたならもうちょっと簡単だった。■昨日のコンテスト成績証。解くべき問題を解いて -5。まあ順当。B 問題が解けたのえらかったと思う。約分なんて高等数学テクニックとか式をにらんでの2の素因数探しとか、そんなんもう何十年も前に忘れてんねん。■■■「そうした結果が本当に辞書順最小かというのは実はよくわからないところだけど……」。この問題の設定においては位置と値が等価だということをよく考えれば納得できるのではないかな。「グループの末尾の位置にあっては多少の妥協をして現在の要素より大きい値を引っぱってくることになっても他所のグループとスワップをしなければいけない」と書いたけど、この「グループの末尾の位置」というのは必ず1を含むグループの末尾のことだし、「他所のグループ」というのは必ず全メンバーが後方を占めているグループのことなので、そういう関係を踏まえればスワップの位置づけがわかる。いや……、考えれば考えるほど「必ず1を含むグループ」であるということが俄には承服しがたいな。やっぱりそうだと思うんだけど。


2023年10月14日 (土) [AtCoder] 今日は日本レジストリサービス(JPRS)プログラミングコンテスト2023(AtCoder Beginner Contest 324)があった。自分のすべての提出。直近はまさかの緑パフォが続いていたけどとうとう実力通りの結果が出たのではないかな。そうは言ってもレートは上昇していて欲しいのだけど、とりあえず結果待ちのあいだに A から F のふりかえりを。■A 問題「Same」。A.all?(A[0]) でも A.uniq.size==1 でもお好きな方で。■B 問題「3-smooth Numbers」。素因数が2と3だけかどうか確かめる。2と3で割れるだけ割って1になるかどうかでわかる。■C 問題「Error Correction」。これ3つの問題がひとつになってるよね。強いて言えば2つは対称な問題だったので、2種3通りの解答を書くのがとても面倒でした。文字数が1つ多いときは、1度だけ比較をスキップできるということ。それで他の全ての文字が一致するなら可能性がある。文字数が1つ少ないときは、文字数が1つ多いということです。■D 問題「Square Permutation」。意外に Ruby での AC が少なかった問題。13 の階乗は数が多すぎるので、平方数の方から攻める。2乗して 13 桁を超えるのは数百万くらいの数からだったので列挙できる。ところでね、サンプルの2に「異なる並べ替え方でも、並べ替えた結果の数が同じなら 1 つと数えることに注意してください」と書いてある。そんな大事なことは本文に書いておけよと思って今読み返してみたら。本文には「(1,…,N) の順列 P=(p1​,p2​,…,pN​) によって i=1∑N​spi​​10N−i と書ける整数のうち、平方数であるようなものがいくつあるか求めてください」と書いてあった。うーん? 順列ではなく順列によって表される整数を数えろって書いてあるのかな? まあいいや。自分のこの提出(#46569450)には順列を数えた部分がコメントとして残っている。無駄な時間を使ったぜ。しかも最初の提出は WA×1 だった。ゼロは平方数に入りますか? 入るみたい。式をよく見ると順列を数える場合でも答えに足すのは固定値なんだな。単に大きな固定値を足すか1を足すかの違いでしかなかったのに、つどつど無駄に数を数えていたのは自分が足りないせいだったな。■E 問題「Joint Two Strings」。これも最初は違う問題を解こうとしていた。この問題の部分文字列とは連続とは限らない部分文字列のことでした。問題文にちゃんと書いてあるんだから、読むだけでなく頭に入れてくださいね。制約が大事。「S1​,S2​,…,SN​ の長さの総和は 5×10^5 以下」と書いてあるのだから、S をなめるような処理を書いてその中で T をスキャンしたりしなければ間に合う。S ごとに T を前から何文字カバーできるかを数え、同じように T を後ろから何文字カバーできるかを数え、足して T の長さより短くない組み合わせを数える。これは罠なんだけど、入力の N は T の長さではありません。今日の入力は、C 問題 と E 問題が共通して変則的だった。なぜ関連するわけでも同種でもない入力を1行にまとめるのか。(たとえ使わないにしても)今回に限って文字列長を先行して与えないのはなぜなのか。入力の処理が面倒だった。■F 問題「Beautiful Path」。比率は扱いが難しい。最終的に分子を最大化して分母を最小化したいんだけど、中間値についてたとえば比率が同じでも (美しさ)/(コスト) = 100/100 と 10/10 を同列に扱ってはいけない。100/100 を 10 % 改善するには美しさを 10 足す必要があるけど、10/10 を 10 % 改善するのには美しさを 1 足すだけでいい。以前に濃度の問題を2問解いている。「Sugar Water 2」(20230319) と「食塩水」(20220714)、それともうひとつ「おまかせ」。それでもやっぱり解法に悩むし 30 分はかかるんだね。途中で G 問題を読んだりなんかもして、でも F 問題の制約が「1アイデアで解けるよ」と訴えていたので F 問題に注力することにした。解法は以前の日記に書いたように、濃度を決め打てば溶質の過不足が具体的な値として求まるので、これを最大化するようにして最終的にゼロを上回ればいい。二分探索で。■コンテスト成績表。遅い6完だったけど青パフォでした。明日の ARC にはいくつのレートを捧げることになるのかな。■D 問題。提出 #46587508 (gmmtea さん / 971 ms)。他の Ruby の提出にほぼダブルスコアの差をつけて1番早い。列挙に工夫があるのかなと思うけど、よくわかんないことをしてる。すごい。■ちょっとお風呂で考えて Send More Money (20210412p01) と共通点があるかと思った。あれは DFS で無駄なく列挙することで4桁 ms が2桁 ms まで劇的に縮んだ問題だった。この問題も2乗する数を1桁ずつ確定できないかなと思った。確定済みの値が cba で次の桁が d のとき加算する値は d000 であり、2乗した数は (d000+cba)^2 = d000*d000+2*d000*cba+cba*cba になる。増分は d000*d000+2*d000*cba の部分。増分の末尾ゼロ3つが確定しているので平方数の下3桁には影響を与えられない。そんな感じで平方数の確定した桁と使える数字とを見比べて違反があれば即座に以降の列挙を打ち切れるのではないかなと。実際にやったけど答えが合わないしサンプルの3が却って遅くなったのでやめにした。


2023年10月09日 (月) [C++] 「Dはmapを舐めている途中に要素を追加したくなる。迂闊なことをするとイテレータが無効化されると思い、事前に入っていなかった値はスキップするという実装をしたが、リファレンスを見るとinsertは既存のイテレータを無効化しないらしいので気にしなくてよかった」。まさにこれ。どこかでみた誰かの解答が range-based for の中で要素を増やしているようで、怖いことをしているなと思っていたのだけど、そうか、許されていたのか。


2023年10月08日 (日) [AtCoder] 今日は ARC166 があった。ABC で惨敗するなら(昨日のこと) ARC に慰めてもらえばいいじゃないの精神で参加してきた。ARC がそんな風にやさしかったことは片手で数えられるほどしかないのではあるが。自分のすべての提出。パフォーマンスもレイティングもしらないよ。A 問題が一生合わへんかった。WA×6 で AC なし! 合間に読んだ B 問題は特に考えることもなく実装を始めてスムーズに AC になったけど、それでも 40 分かかってるのはどこに時間を使ってるんだろう。いや、40 分には A 問題に見切りをつけるまでの時間が含まれている。ファイル(なぜか ABC166_b.rb32 だった)のタイムスタンプによれば作成から 20 分で完成している。すこぶる順調。提出 #46387014 (AC / 507 Byte / 402 ms)。関数を3つ組み合わせてなかなかきれいに解けた。やっていることは組み合わせと並べ替えの総当たり。X 数列の1つの要素を lcm(a,b,c) に合わせる、2つの要素を (a,lcm(b,c)),(b,lcm(a,c)),(c,lcm(a,b)) に合わせる、3つの要素を (a,b,c) に合わせる。A 問題のことは知らない。解けないはずがないんだけど合わない。マルチテストケースは正答との距離が計りにくい点が難しいよね。1ミスがあるだけでもほとんどのテストケースで中に複数含むケースのどれかがそのミスを咎めて WA になるということがありうる。


2023年10月07日 (土) [AtCoder] 今日はユニークビジョンプログラミングコンテスト2023 秋 (AtCoder Beginner Contest 323)があった。結果は見てない。自分のすべての提出。ABCD の4完。E 問題で撃沈。終了後に読んだ F 問題が簡単であまりに残念。崖であってほしかった。ではふりかえり。■A 問題「Weak Beats」。2進数として解釈して特定の値と比較すればいいかと考えてみたけど、偶数桁だけを見ろと言っているのでしかたなく愚直に書いた。■B 問題「Round-Robin Tournament」。添字を含めたペアでソートする。既定では昇順にソートされるので勝利数のマイナスを比較のキーにしてもいいけど、敗北数を数えるとひと手間がなくていい。■C 問題「World Tour Finals」。この前あった World Tour Finals 2022 にちなんだ問題。制約は小さいし愚直にやるだけなんだけど、意外に難しかった。何がって、すでにトップの人の扱いが。でもボーナス点が最低得点未満だということで、総合得点はそれぞれのプレイヤーに固有のユニークな値になる。何も難しいことはなかった、けど 18 分かけた。■D 問題「Merge Slimes」。サイズが倍々で、数は半分半分。貪欲に可能な限り合成を繰り返すことでスライムの数は最小になる。それを効率的に数えられますかという問題。数が半分半分になっていくから操作回数は対数のオーダーになる。愚直に操作をシミュレートして良さそう。操作した結果が既存のサイズのスライムになることがあるから、操作はサイズの昇順に行いたい。プライオリティキューを使いますか? 「キューを2本持つことでプライオリティキューを使わないでもソート済みの状態を保ちながらキューを伸ばせる場合があるというのは、AtCoder について書いた2番目の日記に書いてある」のでそのように。■E 問題「Playlist」。期待値。サンプルの1を頼りに愚直解は求まった。曲を3曲再生するパターンが N^3 通りで、そのうち X+0.5 秒後に曲1が再生されているのは 1+3+3 通り。だけど O(XXN) は通りませんよ。■F 問題「Push and Carry」。非常に拍子抜けする問題。倉庫番。ただし壁はなし障害もなし。位置関係を整理してささっと数えるだけ。最初の提出は変数名の1文字タイポで WA×2 だったけど、3分で修正できた。F 問題が崖でないと救われないなあ。E 問題がうらめしい。でも Ruby の提出を見ると F 問題を解いてる人は E 問題も解いてるみたいなので、E 問題を解けないのが悪いのだな。E と F を両方とも解けてないのが悪い。■■■翌朝。E 問題。最初に考えた解法は O(XN) で間に合う感じだった。でもサンプルの1で 1+1+1 通りは数えられても 1+3+3 が数えられなかった。どうやって ×N するか考える過程で O(XXN) になって TLE が避けられなくなった。ところでね、スタート地点を N^X にして遷移1回につき ÷N のペナルティを払うというのはどうか。あとで答えが合うかたしかめる。■D 問題。みなさんプライオリティキューなど使わずに答えを出している(使うと log が2乗で TLE になるというのはある)。その中でも提出が早めで一番実行時間が短いもの(tinsep19 さんの)を雰囲気だけ読んだけど、その解釈らしきものに翌日になって思い至った。考えなくても湧いてくるなんてお得だ。スライムのサイズの trailing zeroes を処理することで途中で合流するスライムを予め1つにまとめられるのではないか。操作の巻き戻し。操作回数は答えの一部ではないから巻き戻しはタダで行える。あとはソートもいらず初期サイズごとにカウントするだけ。これもあとで答えが合うかたしかめる。■E 問題。どの日記を読んでも特別どうということなく答えを出している様子。最初の O(XN) 解法で分母が1つだと考えたのが間違いだったのかも。つまり、サンプルの1で 1+1+1 通りを数えたと書いたけど、それは (1+1+1)/(何か) ではなくて、1/27+1/9+1/9 だったのではないか。これを解法2としてあとでたしかめよう。以前も書いたけど、確率・期待値の問題って、こうすれば答えが出るという筋道がさっぱり読めないところが弱い。あれこれやってみて正解を導き出す解法にぶつかるのを待っている。当てもんをしている。初心にかえれというのは簡単だよ。全通りを並べてみて、そのうちのいくつが該当するかを数える。その割合。実に簡単。■順番に3つ。□提出 #46376658 (AC / 273 Byte / 393 ms)。F 問題。最初に N^X 通りを計上しておいて、遷移ごとに ÷N のペナルティを払う。□提出 #46376189 (AC / 156 Byte / 193 ms)。D 問題。最初に逆操作をしてスライムをグループごとに統合してから個数の1のビットを数えて合計する。□提出 #46376313 (AC / 233 Byte / 465 ms)。E 問題。ふつーの期待値 DP だった。1/N の可能性を足し上げていく。X を超える遷移については曲1の場合だけ記録するようにして、その他の曲に関しては X 未満までしか遷移させなかった。そうすると DP 配列の X を超える部分に答えが入っている。いやー、これが解けないならどんな期待値の問題も解けないよ。イチからやり直した方がいいよ。早め6完の問題セットだったよ(だが4完)。■■■いま気がついたんだけど、E 問題は期待値の問題ではないよね。確率を問われている。何回期待値と書いただろう。気がつかなかった。一応概念は知っているつもり。リスクに相当するものだよね。(脅威の大きさ)×(発生確率)。(賞金額)×(当選確率)。でも確率と期待値を区別せずに問題を解いているってありえることなの? しかも解けてなかったし。


2023年09月30日 (土) [AtCoder] 今日は ABC322 があった。コンテスト成績証自分のすべての提出。例によって ABCDE の5完。まあまあ早め。つまり 30 分余らせて F 問題が解けなかったと。持っていないデータ構造が必要な気がしたんだけどどうかな。ではふりかえり。■A 問題「First ABC 2」。strstr が使えますかという問題。■B 問題「Prefix and Suffix」。if 文が嫌いなので場合分けではない方法で出力値を得たいけど、両方とも該当するときにゼロを、両方とも非該当のときに3を、というのがもう面倒くさくて考えることをやめたくなる。せめて逆なら。■C 問題「Festival」。A 数列の先頭を適当に弾いていきながら1から N 日目までループを回す。A 数列の末尾が必ず N だということで番兵も添字の範囲チェックもいらなくて助かる。■D 問題「Polyomino」。E 問題と diff が逆転して水色だった問題。自分も E 問題より長い 37 分の時間をかけている。とても面倒くさい問題だった。面倒だけど愚直にやるだけ。嫌いではないよ。箱入り娘(20210121)とかカレンダーパズル(20210527)のソルバーを書いたりしてる。でもこういうのはじっくり時間をかけて整理して書きたい。■E 問題「Product Development」。この DP が緑 diff って怖い。AtCoder の参加者が怖い。DP 配列を用意しようとして困ってしまった。K の上限は高々5だけど、5次元配列はなかなかにつらい。「DP だったんだけど、人類が扱うには次元が高すぎるのではないかな? 自分には無理」と書いたときの次元数は3だった。さらに次元数(K)が入力により可変なのが輪をかけてつらい。添字を K 桁の P+1 進数にエンコードして1次元化することでなんとか扱えるようになったけど、それは人間の理解を助けるための余計な処理であって、460 ms の提出 #46108878 (konayuki さん) より 1.5 倍くらい遅くなってしまった。


2023年09月29日 (金) [AtCoder] 精進。この前の ABC321-F「#(subset sum = K) with Add and Erase」。当日は残り 15 分のうち 10 分を使って愚直 TLE 解を書いていた。5000^2 くらいの計算量だと思ったから書いたんだけど、たぶん3乗だったから TLE なんだろう。そうすると1つの DP 配列を使い回して巻き戻しができないといけないなと消去法的に考えて残り5分で修正を図ったけど、なぜか場合の数に負の数(modulo に近い数)が出てきて時間切れ。今週はこの問題をつねにうっすら考えていた。何を引き過ぎているのか。ところで、ひとつ重要な観察として、DP の遷移の順番には意味がない。+a、+b、+c と操作したものと、+c、+b、+a と操作したものでは結果が同じ。だから -c で巻き戻すものというのは、直前に +c した操作を取り消すものだと考えて良い。何を引き過ぎているのかもうわかりましたね。さっきリンクした TLE 解の 13-15 行目において DP の遷移を表すループ((K-x).downto(0){|i| ds[i+x] += ds[i] })があえての降順なのはなぜか。今ループの遷移結果に対して再帰的に遷移操作を施してはいけないからだ。+x 操作が 0 を x に移すのも x を 2x に移すのもいいが、0 から移ってきた x を 2x に移すのはやりすぎ。DP 配列を遷移回数と同じだけ用意して退屈なコピー操作を書くのもひとつの方法だけど、ループを逆順にして書き込む前に読み込むことを確実にするのも手。巻き戻しをするときはそのような工夫が通用しない。すでに遷移が済んだあとの場合の数から、最終ループで加算した場合の数を求めて引き算しなければいけない。■提出 #46049349 (AC / 276 Byte / 1183 ms)。なんというか、きれいにはまって驚くんだけど、ループを昇順にすることで巻き戻しと再帰的な影響を取り除くことが同時にできる。■「この手の場合の数は母関数です。y^K の係数が場合の数です」というような内容をいくつか読んだけど、残念なことにそれはすでに武器を持っている人にしか役立てられない情報なのだな。(1+x)^N なら x^K の係数は自分でもコンビネーションで求められるけど、今回のように x の部分が何乗なのかいろいろな場合に、いろいろ掛けた結果 x が K 乗になるものがいくつあるのか知りたいとなっても、それこそ DP をして求めるしか方法を知らない。そしてそれができたら今回の問題は解けている。つまり「形式的べき級数解説 | maspyのHP」という武器を持っていない人間にとって言い換えはただの言い換えであって答えには近づいていない。残念だなあ。理解できないんだもんなあ。


2023年09月23日 (土) [AtCoder] 今日はサントリープログラミングコンテスト2023(AtCoder Beginner Contest 321) があった。コンテスト成績証自分のすべての提出。ABCDE の5完遅解き。今回のネックは C 問題と E 問題だった。それぞれ 21 分と 56 分(+ペナ5分)かけている。これは考えていた時間ではない。ひたすらに実装が下手だった。脳内イメージをコードにするプロセスがバグっている。ではふりかえり。■A 問題「321-like Checker」。はい。■B 問題「Cutoff」。制約が 100 以下とささやかなので素直に愚直解を書く。■C 問題「321-like Searcher」。K に1以上以外の制約がないことの意味をしばらく掴みかねた。だから文字列で答えを構築する必要があるのかなとか考えていた。そうとしても読み込む前に K が 64 ビット整数だとは知らせてほしい。なぜなのか。問題の不備なのか。最大の 321-like Number が 9876543210 だというだけのこと。全列挙すればいい。その列挙に 21 分かける自分のおつむに絶望するんですよ。言い訳をするなら、0 と空文字列が現れないようにきれいに列挙することができなかったという事情がある。無視すればいいだけなんだけどね。他所で読んだんだけど、321-like Number とは "9876543210" の部分文字列のことだった。そう捉えられたらもっとスムーズにコード化できただろうなあ。2の 10 乗通りの部分文字列に 0 と空文字列が現れるのも自然なことだとすぐわかる。■D 問題「Set Menu」。考える要素はどこにもない。ソートして P 以上になるペアを弾いて、残っているものの総和と P をいくつか足す。……という処理を一方の数列の各要素ごとに他方の数列に対して行う。両方の数列をソートしておくなら二分探索はいらない。AC まで4分。■E 問題「Complete Binary Tree」。セグメント木をイメージすればいい。ただし要素数が2べきに揃えられてはいない。K の上限が N-1 になってるけど、実際にありうる上限はセグメント木の高さ×2 なので 2log(N)≦2log(10**18)<120。10 万あるテストケースごとに K を変化させながら木を辿って構わない。あるノード k があるとき、これの d 階層下のノードは 2**d*k 以上 2**d*(k+1) 未満の番号を持っている。N と比較すればいくつのノードが該当するかは簡単に数えられる(はずだった)。与えられた X から根までさかのぼりながら、直前までいたノードと逆のノードの下にいくつ当てはまるノードがあるかを数えていく。根に辿りつくまでのあいだに K がゼロになったらそのノード自身をひとつ数えて終わりにする。やりたいことは最初から明確で大枠はすぐにできあがったけど、細部がひたすらバグっていた。最後まで残っていたバグは、「(根までさかのぼりながら、)直前までいたノードと逆のノードの下にいくつ当てはまるノードがあるかを数えていく」処理における「逆のノード」。直前までいたノードが N 以下なのはたしかだけど、逆のノードは必ずしもそうではない。d 階層下にばかり気を取られていて完全に盲点でチェックが漏れていた。ここでの教訓は「ステップも場合分けもまとめられるものはまとめた方が良い。式が3つあればバグは3か所に潜むし、場合分けにより実行パスがテストケースごとに分かれてしまうと、実行されないパスのデバッグ機会が限られてしまう」。d 階層下の処理とゼロ階層下の処理を分けたのが良くなかった。自分で書いたことなので当然わかってるんだけど、コンテスト中は時間に追われるからきれいに完璧に書くことの優先度が下がってしまう。それで AC が遠のいてたら本末転倒急がば回れなんだけど。■F 問題「#(subset sum = K) with Add and Erase」。残りのわずかな時間で考えていた。最初は O(N^2) だと勘違いして愚直に DP をするものを書いた。TLE だった。そうすると DP 配列を使いまわして巻き戻しをする必要があるなと、消去法のように考えた。でもそんなんやったことないし、できるかも知らない。残り1、2分くらいで書き直したものは引き算し過ぎでマイナスの数字(modulo に近い数ということ)が出ていた。


2023年09月21日 (木) [AtCoder] 精進。日曜日に ARC165 があったが不参加だった。調べれば前回の ARC164 からふた月以上ご無沙汰で、参加しないことに後ろめたさを感じなかったのと、レート収支が常に負の ARC にレートを捧げる心構えができていなかったのが理由。■A 問題「Sum equals LCM」。答えが存在しないケースはどういうケースか。和で N を作るのは簡単で、N を LCM を維持したまま分割したときに和が N 以下にできたら、あとは +1+1+1+1+... して N が作れる。問題は LCM を維持したまま N を分割してその和を N 以下にできるかどうか。素数の掛け算で作られる数より和で作られる数の方が明らかに小さいので、とにかく分割すればいい。ただし、ある素因数 P を複数の数に分散させても LCM には寄与しないくせに項を大きくしてしまう。というわけで、N を素数の累乗ごとに分割するのが和を最小にする。それが N 以下なら答えは Yes。だけど例外があって、「2 個以上の (相異なるとは限らない) 正整数」の和で N を作らなければいけないので、素因数が1種類しかないときには1の項を付け加える必要がある。■提出 #45760781 (AC / 150 Byte / 114 ms)。Ruby によるすべての提出を見ると不自然に1秒以上かかっている提出が複数あって、これなんでなんだろうね「AtCoderの新ジャッジ、Rubyの一部提出がメチャ遅い実行時間になっているのだけど require 'prime' があると遅くなるみたいだなー」。■B 問題「Sliding Window Sort 2」。操作について気がつくこと。辞書順最大の数列が欲しいのに、範囲を昇順にソートする操作というのは得をすることがない。良くて範囲内がすでにソート済みだった場合の現状維持。N も K も制約上限が 20 万なので、範囲に対して愚直に線形時間でソート済みかどうか確かめて O(N^2) にしてはいけない。問題名に sliding とか window とか見えるからスライド最小値を使うことを考えた。つまり、ある要素がその要素から始まる K 個の区間の最小値であるとき、その区間は少なくとも操作の候補ではある。操作をしても先頭の要素が置き換えられることがないので、その1点では損をすることがないから。ところが話はもっと簡単で、ソート済みの区間が見つからないときはできるだけ後ろの方で操作をすればいいんだよね(本当に?)。■提出 #45778696 (WA×2)。ソート済みの区間は累積和で探した。サンプルの3によれば必ずしも一番後ろで操作するのが最善ではないとわかるので、直前の項を調べて操作区間をちょっとずつ前にずらすことにした。そうしたらみごとに after_contest に殺された。■提出 #45780788 (AC / 476 Byte / 164 ms)。説明が難しいな。ソート済みの範囲が見つからないとき末尾 K 個を操作の候補にする。だけど、新しく繰り入れる部分が操作による影響を受けない場合に限り範囲を少し前にずらすことができる。またそうすることで範囲から外れる部分を操作の影響から外すことができる。ずらす幅は最大で K-1 個分(※ K 個ずらして問題がないならソート済みの区間を見逃してたってことだ)。繰り入れる部分が広義単調増加(ソート済み)の場合に限る。また、最初に候補とした末尾 K 個のうちまだ範囲内に残っているものの最小値が新たに繰り入れた範囲に(操作によって)漏れ出してこない場合に限る(※この条件が抜けていたのが after_contest にやられた理由)。自分で解かないと何言ってるかわからんよ。結局この部分にスライド最小値を使うことになった。セグメント木でもいいと思う。これが B 問題で水 diff ってマジなのですか。でもまあ、A 問題で水 diff だった Reverse and Count を思い起こさせる問題ではあったかな。そっちの方がひどいね。■計算量のことを考えないなら、操作区間の先頭と、操作により最初に置き換えが起こる位置のペアを考える。置き換えが起こる位置が最も後ろのもので、区間の先頭が最も前のものが答えだと思う。結局のところ、計算量を改善するアルゴリズムを組み立てる問題だった。ケチなことを考えると色々ミスが出るのはしかたないね。