ABC 368
ABC 368 に参加しました。
問題 | A 問題 | B 問題 | C 問題 | D 問題 | E 問題 | F 問題 |
---|---|---|---|---|---|---|
予想 | 10 | 200 | 1,100 | 1,000 | 1,400 | 1,600 |
実際 | 20 | 56 | 368 | 816 | 2,140 | 1,180 |
oj
が動かない……?
確認中です。
エラーログ
abc368/contest.acc.json created.
create project of Hitachi Vantara Programming Contest 2024(AtCoder Beginner Contest 368)
node:events:497
throw er; // Unhandled 'error' event
^
Error: spawn /nix/store/q8gf4f7373l92a5sd472mbxqci1d1v20-python3.11-online-judge-tools-12.0.0/bin/oj ENOENT
at ChildProcess._handle.onexit (node:internal/child_process:286:19)
at onErrorNT (node:internal/child_process:484:16)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted 'error' event on ChildProcess instance at:
at ChildProcess._handle.onexit (node:internal/child_process:292:12)
at onErrorNT (node:internal/child_process:484:16)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
errno: -2,
code: 'ENOENT',
syscall: 'spawn /nix/store/q8gf4f7373l92a5sd472mbxqci1d1v20-python3.11-online-judge-tools-12.0.0/bin/oj',
path: '/nix/store/q8gf4f7373l92a5sd472mbxqci1d1v20-python3.11-online-judge-tools-12.0.0/bin/oj',
spawnargs: [
'dl',
'https://atcoder.jp/contests/abc368/tasks/abc368_a',
'-d',
'test-cases'
]
}
Node.js v20.15.1
A 問題
リストを splitAt (n - k)
して入れ替えます。
main=interact$unwords.f.words;f(n:k:x)=(++).snd<*>fst$splitAt(read n-read k)x
B 問題
Mutable にシミュレーションで解きました。序盤からオセロットですが、オセロットしたくて Haskell
を使っていることもあり、苦渋の決断を踏み切りました。
res <- (`execStateT` (0 :: Int)) $ fix $ \loop -> do
-- 操作完了まで繰り返し
unlessM isDone $ do
run
modify' succ
loop
C 問題
40 分苦戦しました。素直にループを書きましょう……!
D 問題
次数 1 の頂点を消して行きます。 cojna さんの
Binary Heap
をお借りしました。
コードはぐちゃぐちゃになりましたが、手グセを持っていて助かりました。やはり手続き型プログラミングが楽ですね……。
fix $ \loop -> do
whenJustM (deleteBH heap) $ \x -> do
{- ~~ -}
E 問題
hogeeee
F 問題
hogeeee
Splay tree (2)
Splay tree とは何者なのか
No: SplayMap
以前 は map としての splay tree
を作りました。しかし top-down splaying
で集約の計算ができず、単なるマップになったのでした。欲しいやつじゃなかった……!
Yes: SplaySeq
(遅延伝播反転可能 splay tree)
今回は列 (sequence) としての splay tree を作りました。
maspy さんの splaytree.hpp
を写経します。列を木にすると、親が子の集約 (畳み込み) を持つことができます:
セグメント木との主な違いとしては、要素の挿入・削除ができ、区間反転ができます。出ないと思いますが、部分木の入れ替えなども可能です。
区間反転は左右の子を貪欲に swap
して実装できます。また可換モノイドの畳み込みは反転の影響を受けないため、反転の反映は遅延させます。
verify
余談
-
遅延伝搬反転可能乱択平衡二分木
このような強い平衡木の実装としては、競プロの文脈では RBST が人気のようです。和名のカッコよさも一役買っている気がします。また RBST, splay tree に限らず AVL 木のようなメジャーな木でも実現できそうです。
-
直近の Nachia さんの提出
Top-down splaying で同等の機能を実現されていました。集約の計算をどう実装されたのか気になります。
-
★
自作 Set ライブラリ提供 : C++ の std::set が残念な件
列としての splay tree に map としての機能を詰め込み、特にMultiSet
にすると良いぞという記事です。 kth min までの畳み込みができます。これは真似してみたいです。
SWAG (sliding window aggregation)
SWAG は簡単かつマイナ過ぎて解説が少ない気がします。
Stack ベースの SWAG
尺取り方でモノイドの畳み込みを償却 \(O(1)\) で求めるためのデータ構造 (?)
です。群ではなく、逆操作が存在しない点がポイントです。双対右スキャンで壁を作って pop
に備えます。
配列 [1]-[2]-[3]-[4]-[5]-[6]-[7]-[8]-..
窓 [---------------------]
バッファ [5]-[6]
バッファの畳み込み *******
双対右スキャン <--------------
双対右スキャンとは、右から作る左畳み込み (scanr' (flip (<>)) mempty
)
です。造語だったらすみません。
この図において各操作の内容は、
-
fold
双対右スキャンの左端 (<--
) の値 \(\diamond\) バッファの畳込み
-
pushBack
バッファに値[7]
を追加し、バッファの畳み込みを更新する
-
popFront
双対右スキャンの左端 (<--
) の値を削除する (※)
※
popFront
で双対右スキャンが空になったとき、バッファ中の値を双対右スキャンへ移動します。よって償却
\(O(1)\) です。
Deque ベースの swag
push/pop を左右から操作可能にします。これは左右方向にスタックとスキャンを持てば良いです。
右窓 ------------->
左スキャン ------------->
左窓 <-----------
双対右スキャン <-----------
もう pop できない時は、要素を左右均等に振り分けてバランスをとります。これで償却 \(O(1)\)
になるみたいです。未証明……
verify
-
Queue Operate All Composite
187 ms. Stack 版 SWAG です。 Deque 版で解くと 219 ms でした。 Deque でいいか……
-
Deque Operate All Composite
220 ms. Deque 版 SWAG です。
セグ木で \(O(N \log N)\) で良くない?
セグ木で十分だと思いました。競プロ小説を書くなら主人公は SegTree です。
Misc
-
nextPermutation 最適化
gksato さんの PR でMVector
のnextPermutation
が 10 倍以上速くなりました! アルゴリズムの改善が渋いですね。言語アップデートまではコピーしてお借りします。
-
宮崎雄也と音楽の話
が登録者 8,000 人
すごい勢いです。この間まで 300 人でしたが?!
-
Fleshgod Apocalypse の新譜
が出ました
90 秒聴くにはいい感じなんですが……。