問題文を開く
どう頑張っても実装がだるそうでやる気がなくなる
サンプルコードが配布されていることに気づく
そのまま出すと全人類だしてる点数が出る
メンバのメルセンヌ・ツイスターをグローバルに出して時間いっぱい solver を回して一番いいやつを出力する
ここまで 10~20分くらい
提出頻度制限が解除されていたので提出して寝る
470位 1138perf でした
問題文を開く
どう頑張っても実装がだるそうでやる気がなくなる
サンプルコードが配布されていることに気づく
そのまま出すと全人類だしてる点数が出る
メンバのメルセンヌ・ツイスターをグローバルに出して時間いっぱい solver を回して一番いいやつを出力する
ここまで 10~20分くらい
提出頻度制限が解除されていたので提出して寝る
470位 1138perf でした
みんな大好き20TSD, 普通にLSTすれば21くらいまではワンチャンあるけどそれより上はどうすへばいいの?
そんなあなたにJstris! 僕と記録を競いませんか?
テトリスの致死判定について
これは
の2通りがあります
テトリミノは画面外の 21, 22 段目に出現します この出現位置に既にブロックが存在していた場合, NEXTがそこに突き刺さって終わります
画面に映っている1番上の段が20段目です つまり画面外にテトリミノを設置してはいけません ただし, 18〜20段目に設置したミノが画面外にはみ出るのは問題ありません
出現位置と負け判定(旧) - テトリスのかけら - atwiki(アットウィキ)
この記事がわかりやすかったです
まず 20TSDモードについて
上記のものに加えて, TSD以外でライン消去を行った場合にも致死判定を受けます つまり, 連続で何回TSDを打てるのか競えるモードですね
ここまで聞くとどう頑張っても20+2,3回くらいが限界に思えます
実際, ぷよぷよテトリスにおいて最強のAIとの呼び声高い Cold Clear さんでも, 24回が限界なようです
[PPT AI] Cold Clear - 24 T-Spin Doubles - YouTube
人力で24回 (置きミスがなければ25回) を達成している方もいらっしゃいました すごすぎ
【ぷよぷよテトリス2】24TSDs 【20TSD】 - YouTube
しかし, Jstris の仕様を利用することでこの限界を突破できます
それが Line Clipping です!
Line Clipping in Jstris 20 TSD - YouTube
この動画を見ると, 明らかにおかしな点があると思います 既にブロックが存在している場所にミノを置いているように見えますよね
Jstris では, 設置したミノの画面外にはみ出した部分が消える というすごい仕様があるため, このようなことが可能になっています
初めて気づいたときにはバグかと思ったのですが, REN の弱体化のための仕様なのではないか という話もありました
正確には, 22段目以上の部分は消える 21段目の部分はそのまま残るが, 同じ位置に別のブロックを重ねることが出来る
っぽいです 厳密な仕様は知りませんが, いろいろ試した感じ多分これで合っていると思います
方針
とにかくたくさんミノを消したい, できるだけTspinをする場所に積み上げたくない
ということで, ドネイトをします
開幕TSDをしたときの2巡目でたまにやるかっこいいドネイトですが, これは乗っけた分を全部消してるので積み上がりません
このドネイトを無限に行うことで, 高さを稼いでいきます すると余るミノが大量に出てくるので, これを 右三列に積み上げ, Line Clipping で消していくわけです
ドネイトに使わないミノはすべて右三列に積まないといけないので普通に難しいですが, これは慣れるしかないです
ネクストをよく見てドネイトの先読みもして何とかします
何回かこれを挟んで, 限界になったら右の更に 1, 2 列を埋めて普通の LST をする というようなことをすると 30TSD ほど出すことができます
【Jstris】29 TSDs【20TSD】 - YouTube
Line Clipping でミノを消す必要がありますが, 21 段目のブロックは消えずに残ってしまうので, 画面外がどうなっているのか を把握しながら消していく必要があります (特に SZ)
ここからさらに回数を増やすためには, Oミノと Iミノが邪魔になってきます
Oミノが邪魔な理由は, 21 段目は消えないということは高さ 2 しかない Oミノは消すことが不可能 (重ねるのはできるが) なので, どう頑張っても右三列だけでは処理しきれなくなるため, Iミノが邪魔な理由は, どう回転しても右三列に乗らないためです
そこで, Oミノ専用の置き場所を作ることを考えました
このように, 限界がきたらミノをひっかけて2列左に伸ばします
このとき, 右三列は 21段目を埋め, 伸ばした二列は開けるようにします
すると, 次に TSD を打つと二列下がって図のようになります
右三列は Line Clipping をして, Oミノは空いたところに置きます
するとまた先ほどの状況に戻りますね
伸ばした部分が一番下に来るまでこれを繰り返します
この方法の利点は, Oミノの部分は 21段目が開いているので Iミノの致死判定を回避できることです
また, Oミノを置いた後でもどのミノも180°回転を駆使することで右側に持っていくことができます (Zミノの回転法則わかってないですが, なんか越える)
一番下まで来たら, うまく隙間を埋めてあとは LST を頑張ります
こうすると, 50 TSD くらい出すことができます
【WR】52 TSDs in 6:50.853 【Jstris】 - YouTube
暇だったので書きました 暇な人は挑戦してみてください
上手くいった とか もっといい方法見つけた とか ここ教えてほしい とかあったら教えてもらえると嬉しいです
意識してることとかは暇なときに追記するかもしれません
実は出ていた
競プロ自体モチベがなくてそこまでやる気はなかったが, せっかく誘ってもらったので頑張るかぁという感じ
とりあえず最初はABC並列で解くことになっていたが, 何故かAtCoderのレートは僕がいちばん高かったのでCに回される 去年の嫌な記憶が蘇ってきた
前日
気晴らしに去年のC問題を解く 全然いい実装が思いつかなかったので提出コードを見てみた 二分木になることがわかっているので累積和みたいなことをしなくていい(全方位木DPの計算量コーナーケースであるところのウニがない)ということで pair で子供を持って全パターン書いた 割と綺麗にかけたかな?
結構バグったので, 去年の自分だと最初から取り掛かっていても結局解けていなさそうだなぁと思いつつAC 久々に構文解析を書いたのでまぁよし
当日
バイトが入っている日だったので非常に怖かったが, 例年通りの時間だったので余裕で間に合う ついでにMonsterを買ってくる
今年もトラブル起きるかなぁと話しながら待っていると何事もなく始まった 運営さんありがとうございます
Cを開いてみるとなんか普通の問題 とりあえず数列の和を求める関数書くかめんどくさ って思ったが冷静に考えるとただの二乗だった 親切
DPが頭によぎったがどう考えても計算量が落ちない
こんなのどうせ貪欲に長くとって等間隔に切ればいいだろと思って切る個数を全探索するコードを書く 小さいケースがコーナーになってそうなので early return もする
サンプルが合わない 焦ったが冷静に考えると合うわけが無い 植木算ができていなかった 小学生からやり直せ
添字をガチャガチャしていたらAが通ったらしい 自分もサンプルがあったので提出したら通った
合流してDを見る 何故こんな所に NTT-friendly な mod での数え上げがあるんだ
問題を理解したがやばそう DPするしかなさそうだがどう見ても状態数が多すぎる
fps という単語が脳裏によぎった 最近その辺の勉強したつもりだったけどまだまだ何もわからん
とりあえずほかの問題も読んでみることにする
Eを見てみる なんかやばそうなやつを復元するらしい 端っこの列くらいしか埋まる気がしない
Fを見てみる 出たな構文解析 けど構文解析は本質じゃなさそう 全探索は無理だし貪欲も嘘っぽい 激ヤバ区間DPくらいしか思いつかないが計算量がやばそう
Gを見てみる 出たな幾何 決め打ち2分探索にしか見えないが決めうったところで判定が簡単になっている気がしない なんかいい感じの性質がありそうだが見える気がしない
Hを見てみる 変なイラストが見えたが問題文が頭に入ってこない 疲れているのか焦っているのか
そういえばBが解けていないらしい 読んでみるとやるだけっぽいが実装がゴミすぎ 無限にコーナーケースが思いつく
ちょっと書いてみたが挫折した Dに逃げる
後ろからやればいいのではと言われた 確かにそれは嬉しそう けどなんか3次元DPとかになりそう
t の隣接項が減少していたら絶対同じ列にしないとダメと言われた 確かにそう それを削れば単調増加列になると言われたがそれは嘘 3,1,2 のようなケースがすぐに思いつく
3,1,2 は 3,2 じゃなくて 3 にすれば単調増加になると気づいた ホントっぽい
二乗がギリギリ許されてる制約なので愚直に erase するコードを書く stackとかで上手くやれば線形になりそうだけど無視
一生サンプルが合わないが, 削除は上手くできていそう DPの遷移を間違えていた
直したらサンプルが通ったがACが出ない 焦る
まだDPの遷移を間違えていた サンプル合うなよ 投げる ACが出ない
全然バグが見当たらないので, チームメイトをラバーダック代わりにして考察を垂れ流しながらコードを追う
よく見ると自分の出力の行数が明らかに足りていない そういえば si の位置を逆引きする配列のサイズを削ったあとの要素数分しか用意していなかった そのせいで配列外参照してセグフォで落ちていたっぽいかな?
エラー出せよC++ 何も言わずに終了されたので全く気づいていなかった
直したらACが出た 嬉しいが悲しい 1時間くらい無駄にした
順位表を見た感じ後通せそうなのがEくらいしかないので眺める
無理だろこれ かっこ列の存在判定, 復元っぽいけどどう見ても無理がある
線形計画問題に見えてきたのでワンチャンフローでも流すのか? とか考えたがそんなわけない
無理すぎて笑いながらFの構文解析部分だけ書いた
時間切れになったのでTLを見る みんな嬉しがったり悔しがったりしていて楽しそう
東工大は20年振り? とかで東大に勝って1位らしい すごいね
すごいスピードで解説が上がっていたので眺める
Dはだいたい考察通り 問題の E を見ると何も書いていなかった これ解説なんですか? 解説に書いてあることくらいは4秒でわかったが, その次どうすればいいのか全然わからなかった 実力が全く足りていなさそう
Fもだいたい思った通りだった Eに使ってる時間とDのセグフォに気づいていない時間投入したらワンチャンあったかなぁ どうせバグり散らかして間に合ってなさそうな気もする
Regional, 横浜まで行くのめんどくさい… オンラインにならんかなと不謹慎なことを思いつつこれからのことを考えてみると, 去年の問題の感じで来られると良くて1完だなということに気づく
困った どうしようかな 特に問題文が英語なのがやばい 誰か代わりに出てくれ
競プロにおいて分割数は を 個の非負整数の和で表す方法の数 (ただし, 順番は区別しない) であり, 計算量オーダーが である dp が(蟻本などに載っており)有名である
しかし, 一般に数論の世界で分割数というと を自然数の和で表す方法 であり, である
これは同じ dp をすると かかってしまうが, である場合に限りより高速な方法がある
まず, の母関数を考える
を何個使うか, を何個使うか.... ということを考えると,
と書くことができる
と表せるため,
として, の母関数を求めることができた
できたが, 求めるのが簡単にはなっていない
ここで, 右辺の逆数である について考えてみる
これは, オイラーの五角数定理 より
と書くことができる
凄まじく非自明だが, 証明も大変
ヤコビの三重積 から証明する方法, ヤング図形との対応から頑張る方法, Shanksによる天下り式な証明 などがあります 暇だったら書きます
について求められればいいので
と書ける
これは簡単に求めることができて, NTT-friendly な mod でならニュートン法を用いて逆数を で求めることができる
そうでない場合, さらに式変形をする
と
を掛け合わせて
と書ける
の項の係数に注目することで
という式が出てくる
したがって, 漸化式
が得られる
この式を用いて愚直に求めていくことで, で求めることができる
Library Checker さんの Partition Function で verify できる
絶対いらないけど色変したしてきとうに
1152826674点で228位でした
二時間ちょいくらいで取って色も変わったのでコスパ的にまぁまぁかなという気持ち
とても面白そう + めちゃくちゃめんどくさそう
こんかいの自明は白紙提出 Text の AC 数 が増えました
辺を UnionFind に突っ込みながら閉路があったら記録 (既につながっている連結成分を繋ごうとしたら閉路) 残った中で一番大きいやつになんかかけたらおわり
辺を切る操作ができないから動かして変えてってできないからどうしようかなーという気持ちになった
スライドというのを無視してとりあえずあるものを頑張って組み合わせて木を作る → 番号を振ってスライドパズルを解く
をすればいいのかなと思った めんどくさかったのでやめた
山登りみたいなことをしたい
一手ごとに評価していってもあんまり意味ない + めちゃくちゃ時間かかりそうだったので適当な手数進めてよくなったら更新をした 13499173点
局所解がひどすぎる + 時間がめっちゃ余っていたのでてきとうに 20回くらい同じことをして一番いいやつを出してみた 18356575点
どうせならいいやつを深くやりたい → 途中経過を全部保存しといてある程度たまったら score の降順に sort, ある程度で切り捨てて残ったやつで同じことを試す をしてみた → 19322128点
手元実行とか一度もしなかったのでどんな感じに動いてたのか不明
結構時間余ってそうだったし序盤は BFS で全部試してみてもよかったかなーという気持ち
盤面の重複探索除去のために vector<vector<int>>
の比較をしていたが, 制約的に一列併せて一個の int に入りそうだったしそれくらいはしてもよかったかなー
zobrist hash は真っ先に思いついたけどめんどくさいしいいやって思ってやめてしまった
UnionFind 用の配列は一回作ったやつ使いまわせばよかった...
半分くらいバイト中にやったので完璧な時間の有効活用だった
おしまい
Library Checker さんの Subset Sum
を解いたのですが, 日本語の解説がぱっと見なさそう? なので書いておきます
(タイトルに数式を入れる方法がわからなかったので Count Subset Sum としました やり方知ってる方がいたら教えてください)
整数列 があったときに, 各 ] について, 総和が になるような部分列の数を で求めます
みんな大好き形式的冪級数で考えます
を使う/使わない を と表現すれば
としたときに の の項の係数が に対する答えです
さて, これは次数がとても大きくなりうるので高速に計算するのはつらいです
ということで, 積を計算するのはつらいので和に変換します
形式的冪級数の はニュートン法を用いることで項数を として で求めることができるので, を求めることができれば で答えが求まります
ということで を求めます
ここで, のマクローリン展開を考えると
と書けるので,
です 無限に続きますが, 今回次数は あれば十分です
さて, を となるような の数 とすると
と書けますが, 各 について上の式を計算すると計算回数は調和級数で抑えられます
ということでこちらは で求めることができます
全体でみても で求めることができました
【競技プログラミング】形式的冪級数の応用テクニック(前編) - Qiita
https://arxiv.org/pdf/1807.11597.pdf
この辺見たらわかると思います