/ 最近 .rdf 追記 設定 本棚

log[2021-06-28]



20210628() 今日とりあげる競プロ典型 90030 - K Factors(★5★5つでまずまずの難易度だけどRuby で想定解法を通すのは不可能ではないかと思う500 万回までのループならありでも5000 万回のループを Ruby で2秒はなしだと思うかといって組み合わせでどうにかできるのかもわからない定数倍改善の努力の跡>TLE×13TLE×12TLE×7TLE×3サンプルの5が強すぎるのでこれが通れば AC への道が開けそうしかしもう万策尽きている(N, K) に対応した答えを埋め込む?(やらな) ところでCrystal だと素直に書いて 271 ms らしいですよ


20210627() 昨日の競プロ典型 90 077 - Planes on a 2D Plane(★7■実にタイムリーだった過去に蟻本に2度取り組んで2度投げ出しているのだけど(20200602p02.03)しおり代わりのスリップが次はここからだとネトワークフローのページに挟んであるのですねょうど前日にお風呂でページをぱらぱらめくっていたのですぐにこれ「二部マッチングの問題だとわかったというわその言葉と概念を仕入れていたあとは蟻本の C++ドを Ruby に翻訳する簡単なおしごと最初の一歩はこういうのでいいでしょう(慣れてから理解が追いついてくるのを待ってもよいのではないか)提出 #23754353 (TLE×7 / 部分点1+1+2 / 同じ内容) さてどうしよう見よう見まねなのであってなんの策もない実行時間制限が 1.5 秒のところ C++400 とか 700 ms かかるらしいんだよなあ(Ruby に手があるのか?)二部マッチングでTLEに苦しんだ話 - あなたは嘘つきですかと聞かれたYESと答えるブログ


20210626() 「ワクチンを接種した後も感染対策は引き続き必要なのであればQoLは変わらないのでワクチンは打つべきでは無いという意見を見かけて直後素『頭が悪いなら考えなければ良いのに・・・という感想が浮かんでしまった / Twitter■この間違い探しけっこう難しくないですか? ワクチンを接種した場合もしなかった場合「感染しないことを比較の前提にしてしまっていることが間違いかなと思ったけどそんな気がするだ


20210625() 今日の競プロ典型 90取りこぼしてい051 - Typical Shop(★5を通したーワド:半分全列挙をしようと書いてあるのは知っているのだけど解説を読む前の提出がなまじ TLE×1ったせいで捨てるに捨てられなくて今日まで無得点だったしかし意地でとうとう通した>#23736923 (1593 ms / 同じ内容)if k==2 が最後の TLE 対策それも含めて思いつきを全部試してみましたみたいな頭悪そうな雰囲気が気に入っているif k==2 の中身は PairsHandshake の解答のオーダーを改善する過程で出てきた形>20210401p01


20210624() 今日も競プロ典型 90073 - We Need Both a and b(★5 すごく難しいです。解説を読んでも難しいです。diff 後半だARC112-C DFS Game(時間をかけて)解けてもこれはまだ解説を読めばプログラムの型はできていたことがわかる大きなミスはあるドを根とする部分木について考えるとき「単色になる場合」と「二色になる場合を数えるにあたって切り捨てる場合があることに気がつかなくて(解説のこの部(pos,bi)を削除するとき頂点 bi を含む連結成分が 'a', 'b' 両方含む必要がある一方削除しないとき 'a' しか含まないから)必ず単色・二色のどちらかに振り分けようとしていたこと一応 AC>#23696813 (同じ内容concat<< でスタックに二重に積んでる)074 - ABC String 2(★6 前日より★が多いけどこれは★3つくらいのあっさりさで解けた「この桁の変化は(逆向きだけど)すごく見覚えがあるぞ「だけど繰り下がりに伴う変化だけちっと違うぞというあたりから。.tr.to_i+.tr.to_i (@2021-06-28 .to_i 一発(相当)で計算できるこんな言語もあるらしい20012進数で解釈するというのは通常だと意味が通らないがdcにおいては構わず2×2^3が使われる)■今日はこの他に取りこぼしてい045 - Simple Grouping(★6Ruby で通しておいた組み合わせの総当たりが bitDP でできるというのは初めて知ったAvoid War がまだ通せないとは 20210622 で書いたけどそのときに覚えた部分集合の列挙をビト演算で行う方法(蟻本に載っていた144ージ)がさっそく使えた1つのケースだけ 20 秒くらいかかって TLE になるのでその場合だけ別の方法で答えを出すなど>#23710778 (1087 ms / 同じ内容)□わずかな時間を削るためにいろいろと猪口才なことをしている配列の配列を作るときに長さ142^{15}個のイスタスがいいか長さ2^{15}14個のイスタスがいいかと2点間距離をメモした D 配列がそのまま DP 配列(E)の初期値であるとか(だから本当は3ビト以上立っている数に限って列挙したい)DP 配列のその他の初期値が最大値ではなく 0 でいいとかそれによって中間ループを K 回回さないで済んでるとープの中で最初から最後まで使われている d 変数の初期化が実は1回だけですよと最内ループの C if A && B が多少冗長ではあるがコトの順に並んでいて総合的には得するだとか(少なくともローカルでは)しかし点を一列に並べて端っこから2番目の点を無き者にしてループの指数を1減らす試みは失敗した


20210622() 競プロ典型 90072 - Loop Railway Plan(★4■テトケースが甘々だから通ったけど16×16 トだけのケース(自作)を通せる解答が作れなかったこれ023 - Avoid War(★7の2点小課題(1H,W17)が未だに通せない理由なんだけど(っ白の盤面が壁になっている)72 問目では許されてしまうの


20210620() RubyAtCoder をやってるとよく見かける名前と同じ人が Ruby に速度改善パッチを投げていた(ということに気がついた)すごいこれで Ruby で勝てる(そういう話か?)


20210618() 「左の問題を中2に出したら3分後に右の解答が返ってきて絶句した https://t.co/hFaGZQbc3j / Twitter■あかん定積分わからへんそれだけの情報で面積求まるの?っていうのが最初の感想範囲が -1 から 1 までってわかるのに気がついてx2-1(用語不明)x3/3 だから1-1 を……どんな式に代入するのか思い出せない13/3-(-1)3/3 だと思ったけどそれだと 2/3 なので4/3 (図中)でも 1/3 (訂正ツイ)でもない■ところで錐体っていつ習う? 覚えがないX 軸を無視してるのが良くない気がするつまり斜線部っていうのは二次関数だけでなく X 軸と組み合わさってできあがってる範囲なわけだから……(どこをどう修正したら 1/3 になる?)■謎は全て解けた! x2-1(用語不明)x3/3 でなく x3/3-x微分のつもりで定数項を捨ててはいけないこれに……?X 軸に沿って積分をする-11dx が幅高さにあたる値は y=0y=x^2-1 の差でありy=0 の方が範囲内では上だからこう 0-(x^2-1)面積は縦×横だから -11[0-(x2-1)]dx(用語不明)して 1-1 を代入して-(13/3-1)--[(-1)3/3-(-1)]=2/3+2/3=4/3だいぶ思い出したのではない1/3 との訂正ツイトは違う部分を訂正していたものと思う(よく見たら 1/3 「体積ってね)


20210617()

最終更: 2021-06-17T19:54+0900

[AtCoder]競プロ典型 90035 - Preserve Connectivity(★7

解説はこちら>解説1解説2解説3

 LCA とダブリング

実装したことはないけどダブリング(要は繰り返し二乗法でしょ?)で効率的に親を辿る?と書いたのがつい先月のことだけどとうとうダブリングを実装する機会が訪れた

この問題がどうして選ばれた複数の頂点を決まった順番で環状に並べて隣接する頂点ペアの LCA が辺の本数になって割る2が答えになるのかは解説3を読む今は LCA にだけ注目する

LCA の取り扱い巨大企業」や筆塗りで経験があるけど線形より効率的な LCA の検索が案外面倒くさい最小共通祖先 [いかたこのたこつ]にいくつか手法がリトアップされているけど自分が知っている手段はセグメト木だけでありセグメト木は書くのが面倒くさい

そこでダブリングです。

 提出 #23482710 (TLE×26 / 810 Byte / 2207 ms / 42608 KB) ※まだコンテト期間中であり見られないはず。

間違えた(TLE)

21
22
23
24
25
26
27
28
29
30
31
32
33
34
A = [ps=P.dup]
(D.max-1).bit_length.times{ # 1世代上はすでに P としてあるので、1回分繰り返しが無駄かも。
	A << ps = N1.times.map{|a| ps[ps[a]] }
}

Ans = lambda{|a,dd|
	i = 0
	while 0<dd
		a = A[i][a] if 0<dd&1
		dd >>= 1
		i += 1
	end
	next a
}

A 配列に事前に親親の親(2世代上)4世代上8世代上とメモしておいてAns 関数(Ancestors の略ったら略)add 世代上は?という質問に対数時間で答えられるようにしたAns 関数がこのようなインタフースになっているのはLCA を経由した2頂点間の辺の数を求めたい呼び出しもと「同じ深さにある2頂点 a,b が初めて祖先を共有する深さは?という問いを立てて二分探索でその深さを確定させようとしたから次のように

35
36
37
38
39
40
41
Dst = lambda{|(a,b)|
	da,db = D[a],D[b]
	dc = (1..[da,db].min).bsearch{|dc|
		Ans[a,da-dc] != Ans[b,db-dc]
	}
	next dc ? da-dc+db-dc+2 : (da-db).abs
}

競プロにおいては対数は定数と言われるけれどかなり大きな定数ではあり必要がないところで log をくっつけると TLE に苦しめられたりする>Pairs同じ日記に書いてあるけど「射撃王」やHandshakeのように余分な log があっても TLE にならないこともある

 提出 #23482781 (AC / 873 Byte / 1082 ms / 42672 KB) ※まだコンテト期間中であり見られないはず。

A 配列は正しくはこう使う共有されている yuruhiya さんの解答 を見ても LCA#lca メソドが同じ感じだったので大嘘はついてないと思う(DstDistance の略DDepth)

35
36
37
38
39
40
41
42
43
Dst = lambda{|(a,b)|
	da,db = D[a],D[b]
	a = Ans[a,da-db] if db<da
	b = Ans[b,db-da] if da<db
	A.reverse_each{|ans|
		a,b = ans[a],ans[b] if ans[a]!=ans[b]
	} if a!=b
	next a==b ? (da-db).abs : da+db-2*D[P[a]]
}

実は解説2にはこれを説明する具体的手順が書いてある(あとで詳しく読んだ)だけどありとあらゆる落とし穴にはまりたがる自分にとって「こうすればいいんですよ「こうしてはいけませんよいうドバイスは役に立たないんですな「要は繰り返し二乗法でしというだけの理解で実装してみて「あれは良かったここはダメだったと納得するまでは身にならない仮にドバイスのおかげで最初からうまくやれたとしてもそれは今回だけのことであり将来必ず自分の性向に導かれて穴にはまる早いうちに地図を作っておくべきだそうすれば多少は


20210616()

最終更: 2021-06-21T21:06+0900

[AtCoder]競プロ典型 90068 - Paired Information(★5

すごく難しいです。答えの出し方に確証が持てないままとりあえずグラフとして解答を書いたクエリ0に応じて辺を追加するクエリ1に応じてドの値を確定しながら X から Y までグラフをたどるしかし TLE

 提出 #23506723 (TLE×10 / AC×3) ※まだコンテト期間中でありアクセスできないのでこっち>提出 #23506723.rb27

次にクエリ0では Y=X+1 だという制約を思い出してグラフを配列上に配置したしかしこれでは多少効率が良くなれど TLE は解消しない制約はド数(N)クエリ数(Q)ともに上限が 10 万であり1つのクエリに答えるのに線形時間をかけることができない

局所の変更を全体に(対数時間で)波及させるのに BIT がまず浮かぶ何を記録しよう階差の累積値かなと思ったつまり連続する3要素 A,B,C があり2度のクエリ0によって A+B=S, B+C=T であるとわかっているならC-A=T-S から1つおきの2要素の差が直接にわかるこれの累積を記録しておけばクエリ1で XY2×k はなれていても直接計算できる

 提出 #23510943 (AC / 669 Byte / 413 ms / 31888 KB) ※まだアクセスできないのでこっち>提出 #23510943.rb27

結局 BIT は使わなかったクエリへの答え方は階差の累積という点で同じだけどクエリの先読みをすれば事前に累積値が記録しておける更新がないなら値の取得に対数時間がかかる BIT よりただの配列の方が良いAmbiguous と答えるタイミングは Union-Find で管理した

 《上級者向(★7X[i] + 1 = Y[i] の制約を外した場(ワナにとても引っ掛かりやすいです

階差を使う解法は完全Y=X+1 (T=0 の場合)という制約に依存しているのでっかかりを失って困ってしまったグラフなら困らないが TLE階差を封じられてどうすればよい

 A_1A_2……A_{N-1}A_N の関係性がすべて分かっていた場合A_1 の値を +1 すると下図の通り +1 される要素と -1 される要素があります

解説が公開されたプラスかマイナスかそんな単純な関係やったんそれにしてもそこからさらに(厳しくない方の)制約をクリアさせられることがもうつらい

Y=X+1 (T=0 のと) という条件が外れた厳しい方の制約だけどX から Y へ至る異なるパスがクエリ0によって与えられたときにどうすればいいかわからないでいる定数時間で答えるためにどのような情報の持ち方をしておけばいいのか(グラフは TLE)でもプラスかマイナスかという単純な関係なのならばすべてのパスに関わるドをまとめて詰め込んでおいてつじつまが合うのだろう

連結なド間であるドを基準(たとえばゼロ)にして相対的な値を割り振っておくド間の距離(の偶奇)も記録しておく迂回路があっても分岐点・合流点のドが持つ相対値はパスによらず共通だしパスによって異なる非共通ドもド数の偶奇はたぶん同じになるまだよくわからないのは連結成分ごとに基準となるドが必要だけど連結成分同士が連結するたびに基準と相対値のふり直しをして許されるのかというところ小さい方の連結成分を選ぶようにすればいいのだろうけど

全部 Union-Find に乗せたいけどうまくいかないUnite は当然としてFind で集合の代表を書き換えるタイミングでもごにょごにょすると集合の合体があったとしても偶奇と相対値を適切に(新しい代表を基準にして)更新できると思うんだけど符号で死ぬほどバグらせる一見正しい答えに見えてもバグ×バグ=正常だったりする

 https://github.com/monnu123/atcoder_files/blob/master/kyopro90-68.cpp (monnu さん / C++ / 166 ms)

自分がやりたいのはたぶんこういうのっぱりできるんだね不可能をやろうとしてるのでないとわかったのは朗報

ところでRuby のようなスクリト言語と C++ の実行時間が接近しているときは入出力がネックになって C++ の実行時間が遅くなっている印象があるC ランタイムとの連携を切ったりstd::endl が引き起こす flush"\n" で回避したりいろいろ対処法がある模様

 https://github.com/NachiaVivias/kyopro-tenkei-90-submit-nachia/blob/main/shared-solutions/068-Paired-Information/068-01.cpp (Nachia さん / C++ / 51 ms)

っちの見た目すっきりな方はすっきりしすぎてて自分がやりたいことと同じなのかどうかもわからない

ド数が 2N あるなあ前半 N 個と後半 N 個の位置づけとは

偶数世界と奇数世界? これはド番号 X が偶数か奇数かという話ではなく二部グラフの話なのであってあるX を赤色で塗った場合と白色で塗った場合を同時並行で扱っているのではないかという……あてずっぽうです。

 提出 #23560415 (AC / 778 Byte / 334 ms / 16544 KB) ※まだアクセスできないのでこっち>提出 #23560415.rb27

った! うんざりするほどバグらせてついに完成した(UnionFind 全乗せ版)頭が整理されたところでバグまみれを捨ててイチから書き直したのが良かったと思う(それからもバグらせたんだけど)

10
11
	D[a] *= D[g]
	V[a] += D[a]*D[g]*V[g]

↑ここは無駄なことをしてる修正版はこう↓

10
11
	V[a] += D[a]*V[g]
	D[a] *= D[g]

Union-Find でグループの代表とサイズを管理するのはこれまでのおなじみだけど同時に代表からの相対値を記録するのは考えたこともやったこともなかった「重み付き UnionFindというものがあるらしいがったい何に使うものなの

ド数が 2N のすっきり解法は遠くから拝むだけにしておきます。

 https://gist.github.com/masa-aa/4be96f053457dc60625a3552288fb1e4 (masa_aa さん / PyPy3 / 304 ms)

これも重み付き UnionFindド番号の偶奇を利用すれば別途偶奇の管理をする必要がないらしいクエリへの応答部分でだけ偶奇を気にすればいいというのがよくわからないがたぶんこれを考えた先に Nachia さんのサイズ 2N のグラフがあると思う

偶奇を一体でぐちゃぐちゃ扱う(自分)→偶奇に前提をもうけて整理されたグラフを作る(masa_aa さん)→偶奇と奇偶を並行させて偶奇の別を気にしない(Nachia さん)という違いなのではないかという印象を持っている

find メソドで再帰呼び出しをしていないスタックオーバーフローのおそれがないのはいい

これだけの学びがあるのは企画の趣旨に照らして(そうでなくても)すばらしい良問だったのでは?


20210612() 競プロ典型 90065 - RGB Balls 2(★7■サンプル3で7億回ループする提出を投げた実行時間はお察し(桁が2つ多い)部分点 3+2ここからは問題をとらえ直す別のフレームが必要な感じ(=全然わかんないって言ってる)■解説2ofしかしこの考察だけだと満点が取れません次にどうすれば良いのでしょう「はいどうすればいいですか?解説3ofーワド:畳み込みを知っていますか? 名前は知っているFFT 怖い(未知のものへの恐怖)『これなら分かる応用数学教室という本を持ってるだけは持ってるんだけど16年間積んでいるっちゃんいかの人がおすすめしていたときに買った

最終更: 2021-07-12T20:54+0900

[AtCoder]東京海上日動 プログラミングコンテ2021AtCoder Regular Contest 122)A,B,C

 A 問題 Many Formulae

A 数列を後ろから見ていく方針は早くに決まったのだけど初項を [1,0] ではなく [1,1] にしていたミスでいつまでも答えが合わなかったあと余りを取り忘れて 1 TLE

 提出 #23369338 (AC / 147 Byte / 106 ms / 24936 KB)

もう 54 分経っている

 B 問題 Insurance

A 数列をソトすれば賢く答えが求められそうだけど何も考えずに探索しても良さそうこの前の ABC204-E Rush Hour 2 と違って最初から実数解が求められているあたり罠もなく素直なのでは?

デバッグ出力を消し忘れて 1 WAbsearch メソドで極小値を求めようとして 1 WA三分探索(名前だけは知っていたが初めて書いた三分探索を救いたい - Qiita)100 回試行しようとして 1 TLEっくり半分の 50 回にして AC本当は探索範囲の幅が許容誤差以下になったかどうかを終了条件にすべきだったそれもダメ?

AC までおおよそ 30 分だから B 問題は A 問題より簡単

 C 問題 Calculator

盲滅法な探索では時間が足りない考えても時間の無駄なので興味本位で解説を読んだ>C - Calculator 解説 by maroonrk_admin

ボナッチ数? 競プロ典型 90でも見かけたこの数列がどうして頻繁にあちこちに登場するのかわからない限りなくありふれたジェネレータなのか(知らなかったけど A 問題にもボナッチ数が現れていたらしい)あと計算途中で1を足すという行為が新しい系列のボナッチ数列を開始することそれらずれたボナッチ数列を串刺しにした和が数列として現れるということもあまりピンとこないそうなの? そんなこと漸化式を見てわかる? 足し算とはそういうものだと言われたら言葉がない私は足し算がわかりません

とりあえず実験をしたx,y=1,1 を初項として操作3と4を繰り返すとどのように値が増加する大体 80 数回で N の上限を超える今度は x,y=0,0 でスタトして 80 数回の1か所でだけ +1 をすると80 数回の操作34の結果がどういう値になるのかを調べたこれは並べるとボナッチ数列になった

つまり次の提出における A 数列というのはボナッチ数列を貼り付けたものではなく+1 するタイミングによって操作3と4を繰り返したのちのちにどれだけの影響を及ぼすかというのを予め調べた実験結果なのである

 提出 #23379308 (半分くらい WA)

貪欲をすればよいと解説に書いてあったので貪欲をしたボナッチ数列の増加のしかたを見れば組み合わせでどんな数字でも作れそうな雰囲気はある(基数の冪乗を大きい方から取っていくのと同じように)

この時,ii+1 両方で操作することはありませ なぜなら,は読み飛ばした解説の細かい部分にこだわってもわかりません

WA の原因は問題を読み誤っていたことxy のどちらかが N になればいいと思っていたがそうではない

 提出 #23379741 (AC)

xy を取り替えればいいのだから仮の操作列を作ってから必要に応じて操作1と2操作3と4を交換するようにした最初からきれいな解答を作ろうという努力はあきらめている

ARC-C が自分のいるところからどれだけ高くにあるかは垣間見られたのでは? 時間内に B 問題まで解けただけで上出来なのにレイングは下がるんですよ緑に対してあまりにひどい仕打ちAB がどちらも茶 diff だといってもARC に参加する層にとっての茶 diff だという意味でABC の茶 diff 問題とはくらべられないと思うんだへなちょこながら ARC に参加する意気にレイングで報いてほしい(嘘です)

それもダメ? [[実数の二分探索・三分探索はループ回数を決め打ちしようね - えびちゃんの日記|https://rsk0315.hatenablog.com/entry/2020/04/29/155009]]探索範囲が過大(過小)な値に寄っていったときに浮動小数点数の密度が足りなくなって無限ループする? 無限ループしていないことをもって OK としていい?


20210610() 競プロ典型 90062 - Paint All(★6■これは知識が問われないという点で好き体感は★4つ直近の ABC-D (解けないくらい難しい)より易しい感じ問題の設定が人工的ですごく頭に入りづらいのが苦労するけど「白いボールが1つでもないと黒く塗れないのに全部を黒く塗るには……というところに気がつければ十分あとは経時的に見「塗れる→塗れないの2つの状態しかない


20210607()

最終更: 2021-09-14T17:27+0900

[AtCoder]競プロ典型 90059 - Many Graph Queries(★7

AtCoder タグを付けてるけど非公式コンテトです。

この問題はとっかかりがなくて最初から解説を読んだ>解説1解説2解説3

 ーワDAG を使いこなそう

この問題で扱われるグラフは DAG (有向非巡回グラ) といわれるものでサイクル() を含まない有向グラフです。

っ? どこに閉路を含まないって書いてあった? 問題文を3回読み直して気がついた

i は頂点 Xi から Yi に向かいます。

制約 1Xi<YiN

制約が持つ情報量が多すぎて見逃していた難しいそして閉路が含まれてるなら含まれてるで解説3に書かれている強連結成分(SCC)分解を手段として持っておくべきであると

 提出1 (TLE×6 / 3325 ms / 461844 KB) 得点 2/7

まだコンテト期間中だけどソースコド共有の動きがあるくらいなので隠す必要はないかなと>解説が公開されたらースコドを共有していきましょう

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
N,M,Q = gets.split.map(&:to_i)
B = 60 # Bignum に切り替わらないビット数を。
Z = (N-1)/B+2
V = Array.new(N+1){|a| [0]*(Z-a/B) }
E = Array.new(N+1){[]}; M.times{
	x,y = gets.split
	E[x.to_i]<<y.to_i
}

N.downto(1){|a|
	va = V[a]
	va[-1] |= 1<<a%B
	E[a].each{|b|
		V[b].each_with_index{|v,i|
			va[i] |= v
		} if va[a/B-b/B-1][b%B]<1
	}
}

puts$<.map{|ln|
	a,b = ln.split.map(&:to_i)
	next %w[No Yes][V[a][a/B-b/B-1][b%B]]
}

2枚目の解説画像で満点解答のため「ビト演算で 64 倍高速化と書かれていることからRuby で満点解答が望めないのは明らRuby を使うことによる定数倍のハンデが最初から 100 より大きいので……手元では V = の初期化部分だけで23秒かかってるもんね部分点2で満足している

AtCoder はスクリト言語に優しいので定数倍高速化がキーになるのは非公式コンテトならではかな解説が大いに参考になる

昨日の ABC204-D - Cooking の解法はどこか(解説1)で見たような形だなあと思いながら書いていた(この日記を書いてるのは月曜だけど典型90-059の出題は土曜日だったので日曜の ABC の前に取りかかっていた)

 解説と違う点

ーワドからこうだろうと最初に思いついた方法で実装したら解説とちっと違うって良くない

最初にすべての頂点について到達可能な点を(ーにビト演算を使って)調べてからクエリに定数時間で答えるというのがさっき貼り付けたスクリトだけど解説ではクエリを 64 並列で調べるようにしていたクエリが起点にある

調べたら重いケースでは頂点数(N=100000)クエリ数(Q=100000)に対して実際に到達可能性が参照される頂点の種類が 84000っとになるものがほとんどだった(例外が 99999)16000 の頂点に関しては到達可能地点を調べたのが無駄だったまあ無駄を省こうとするとスタックオーバーフローを避けてごてごてと記述と条件判断が増えるわりに2割も違わない(それも入力依存)という見かたはできる

必ずしも良くないばかりでもなくて頂点数 N に比して辺数 M が大きい場合想定解法の方が遅くなる

 提出2 (MLE×1 / 1154 ms / 1244032 KB)

基本は提出1と同じ3060トでテーに区切っていた最大で 10 万ビトになりうるビトフラグを1つの Bignum にまとめた

多倍長が許されるのは数百桁までかなと思ってたんだけど(最大で)10万桁でもすっごく速かったしかしメモリ制限 1024 MB を超えて 1.24 GB 使ったところで MLE

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
N,M,Q = gets.split.map(&:to_i)
E = Array.new(N){[]}; M.times{
	x,y = gets.split
	E[N-x.to_i]<<N-y.to_i
}
V = [nil]*N
N.times{|a|
	va,bs,b = 1<<a,E[a]
	va |= V[b] if va[b]<1 while b = bs.pop
	V[a] = va
}

$<.each{|ln|
	a,b = ln.split.map(&:to_i)
	puts %w[No Yes][V[N-a][N-b]]
}

頂点番号とビト位置の対応を逆向きにしたのが工夫(提出1でも Z-a/B という形でやっていた)たとえば N-1 番目の頂点が N 番目に移動するというのを 0b11 で表現すれば Bignum はいらないこれを素直に 1<<N-1|1<<N で表していたらほぼ全ての頂点で N 桁の Bignum が必要になってもおかしくない(頂点1以下全ての頂点が頂点 N に遷移する場合)しかしあえなく MLE工夫なしだと 1.29 GBったから 50 MB だけ減りましたよ

たぶん Bignum のネックは桁数に比例する部分ではなく100 桁であれ1万桁であれ必ず必要になる基礎的な部分でのコトなのだろうその面では 64ト版が不利だBignum か非 Bignum かで見れば上の段落で改善するのは 10 万頂点のうちの 62 頂点程度に過ぎない桁数部分での寄与は小さい

 提出3 (AC / 2009 ms / 500612 KB) 得点 7/7

これは提出12と違って想定解法と同じ方針ただしクエリ 64 並列ではなく 10 万並列でやっている

DP がしたいのに Bignum を頂点の数だけ保持すると MLE になるのをどうすれば良いTLE を避けたいなら Bignum を使うしかないがどうすれば良い頂点番号の小さい順にどんどん処理を進めて使用済みの情報は辺もクエリも遷移してきたという DP 要素もどんどん捨てていった一時的には C 配列に処理待ちの Bignum が蓄えられるけどどこかから遷移して来るまではそれも 0 (Fixnum)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
N,M,Q = gets.split.map(&:to_i)
E = M.times.map{ gets.split.map(&:to_i) }.sort_by(&:first)
A = Array.new(N){[]}
B = Array.new(N){[]}
Q.times{|q|
	a,b = gets.split
	A[-a.to_i]<<q
	B[-b.to_i]<<q
}

r = 0
C = [0]*N
N.times{
	as,bs,c,q = A.pop,B.pop,C.pop
	c |= 1<<q while q = as.pop
	r |= c[q]<<q while q = bs.pop
	C[N-E.shift[1]] |= c while e = E[0] and e[0]+A.size==N
}

Q.times{|q|
	puts %w[No Yes][r[q]]
}

Ruby で満点がありだったのだなあ道具のせいにしてあきらめなくて良かった

 提出4 (AC / 1376 ms / 383080 KB)

メモリもタイムもさらに良くなった提出3がベースだけどクエリごとに1ビトを使うのではなくスタト地点 A が共通するクエリが同じビトを共有する

こちらを参考にして

昨日はうしさんのライブラリを参考にして解いたため(A_i,B_i)というクエリを処理するときにはdp[A_i]|=1<<iとしていたそうではなくdp[u]|=1<<uとしすべてのペアについて問題を解くことにすれば頂点番号uに対しては1..uに対応するbitしか保存しなくてよいため必要なメモリが\frac{N^2}2くらいになるらしい

2021/05/31-2021/06/06 - kotatsugameの日記

頂点番号が小さい順に処理をするという提出3の流れと頂点番号が小さいものから0に近いビトを割り当てるというのがマッチしてトの同時使用量が節約できる

整理したからそのまま同じではないけどだいたいこんな雰囲気>typical90_59_nosub5.rb27

@2021-09-14 結局最後のも提出した>提出 #25841973 (1149 ms)