AtCoder Beginner Contest 251 参加記録
コンテスト中AC:A〜C,E
E - Takahashi and Animals
グラフの問題として考えていたので、言い換えておきます。
頂点について、頂点と頂点の間には辺があり、そのコストはです。
ここから、以下の条件を満たすように辺をいくつか削除します。
- すべての頂点の次数が1以上
残った辺のコストの総和をスコアとする時、スコアの最小値を求めてください。
辺がある時とない時で状態が2通りしかないので、の小さい方から順にdpができないか考えます。
辺の状態がの時のスコアの最小値。但し、
の時、辺は削除されている
の時、辺は残っている
遷移について、辺番目が決定しているとして、辺を考えます。
辺を残す場合
辺は削除されていても残っていてもよいです。従って、
辺を削除する場合
辺は残っている必要があります。そうしないと、頂点の次数が0になります、従って、
このように遷移していけば解けるかのように思えますが、例えば、の時の初期値を
として、と更新していくとで困ったことになります。というのも、
辺が存在する場合でも、辺が存在しない場合には辺を残さなければならず、前述の遷移通りいきません。
これを解決するためには辺が残っているかどうかの情報があれば良いので、DPテーブルに追加します。
辺の状態がであり、かつ、辺の状態がの時のスコアの最小値。但し、
の時、辺は削除されている
の時、辺は残っている
の時、辺は削除されている
の時、辺は残っている
遷移は、の両方の場合が必要になるだけで、先程と同じです。
辺を初期値とします。
としておきます。(は矛盾しており、あり得ない状況です。)
このDPをまで順に更新します。
辺の状態は、辺の状態に従います。
辺のいずれか一方が削除されている場合
頂点の少なくとも一方は次数0なので、辺は残す必要があります。よって、この時は、
辺の両方がある場合
頂点の両方とも次数が1なので、辺は不要です。よって、この時は、
最終的な答えは、です。
提出コード
ABC250E Prefix Equality(ABC250 参加記録)
コンテスト中AC:A〜D
Eはコンテスト後に解説を読み、自分がコンテスト中に考えていた発想で問題なさそうだったので、その方針でなんとかACできました。
E問題について書いたので、記事のタイトルはEをメインにしました。
E - Prefix Equality
自分の実装
こちらの解説と多分同じ考え方だと思います。(多分)
方針
大雑把なイメージです。
から得られる集合をとします。同様に、から得られる集合をとします。
と等しいが存在すると仮定し、その中で最小のをとします。
と増加させ、を追加していくと、そのうち集合として等しくなくなります(但し、便宜上にに含まれない値があるものとします。)。この時のをとします。
この時、に対しては、を満たすが全て等しくなります。
よって、各について、の区間を前計算しておけば、各クエリにで答えられます。
前計算の計算量
愚直に各について、の区間を求めようとすると、少なくともくらいにはなってしまいます。
しかし、実はと探索していくと、の探索範囲も増加するだけになり、結果としてくらいになります。
具体例と共になぜそうなるか書いていきたいと思います。
前計算の処理
以下の数列を例にします。
(-1は番兵)
以下の集合を定義します。
: に含まれ、ではまだ見つかっていない値の集合
: とに共通して存在する値の集合
について、の先頭項との先頭項が等しくなるようなの区間を求めます。
初めとしておきます。
(1) にを追加し、これに対応するの区間を求めます。
であり、に一致する値がないので、これに一致するの区間は存在しません。
(2) にを追加します。です。
なので、からを削除して、に追加します。も同様です。
ここで、が空になりました。これは、となったことを指します。よって、のときに集合が等しくなる時の下限はです。 下限が見つかったため、上限を調べます。
現在、です。
はに含まれるので、となります。
次のはに含まれないので、この時点で、となります。従って、半開区間がの時に集合として等しくなるの区間です。
(3) はに含まれ、更にが空です。よって、は一個前のと等しく、かつ、にはの区間が存在していることがわかります。
この場合、であることから、についてのの区間はの時と同じになります。
(4) をに追加します。この時、新たにの区間を再探索しますが、からの探索として良いです。
なぜなら、はに含まれるため、を集合として等しくするために必要になるからです。また、はに含まれない最初の値なので、ここから探索を開始する必要があります。
の区間の探索をしますが、で、これはに含まれません。よって、と等しいの区間は存在しません。
(5) はに存在するので、既にの両方に共通して存在しています。そのため、には追加しません。
の区間の探索をしますが、で、これはに含まれません。よって、と等しいの区間は存在しません。
(6) をに追加し、となります。
の区間を探索すると、と進めると、両方に含まれるので、から削除し、に追加します。の時点でが空になったので、が、と等しくなる下限です。
上限ですが、番兵として入れてあるがに含まれないので、の時は、が該当の区間になります。
以上で、全てのに対するの区間が求まりました。
例で示したように、は常に、の項目までに含まれない最初の値を指すようにしておきます。
すると、目項までと等しい区間を探す際にから開始すればよくなります。
なぜなら、と等しい区間を探す際に、はを部分集合として含むため、少なくともと共通な値のみを含むが必要となるからです。
これで、は増加させるだけでよいことがわかりました。
Zobrist Hash
公式解説にあったので解いてみました。
整数を乱数に変換します。これをとします。
集合のハッシュ値をと定義します。
また、数列の項目までからなる集合から計算されるハッシュ値をそれぞれとします。
するとi番目のクエリは、
- ならyes、そうでなければNo
と判定できます。
の計算方法については、累積的にXOR和をとっていけばよいのですが、一点注意が必要で、同じ値を2回以上XORを取らないようにします。(偶数回とると、0になるため)
Bonusの問題は、単純に区間のXORをとっても上記の問題を解決できないので、わかりませんでした。
ハッシュの衝突に関してはyoutubeの公式解説では、64bit整数ならくらいになるそうです。
なお、実装では 、 http://vivi.dyndns.org/tech/cpp/random.html
↑を参考に64bitのメルセンヌ・ツイスタに乱数をseed値として与えて生成しました。
ARC139 参加記録
コンテスト中AC:A
A - Trailing Zeros
説明のため、二進数10桁しかないと仮定します。
例えば、の時、??????1000
となり、?
の部分が未確定です。
この時、??????
の部分は、000000〜111111
があり得ます。
000000, 000001, ...
と増加させていくと、ある境でとなり、以降全てこれが成立します。
よって、この境界は二分探索可能です。
最大何桁目まで考慮するかですが、問題文にも特に言及はなかったので64bit整数に収まるだろうと推測し、60桁としました。
ACできたので、問題なかったようです。
コンテスト後に最大桁数について考えてみました。
が最大となるのは、かつ、がいずれも40の場合だと思います。
100...0
が0〜41桁目までありますが、一旦無視して42桁目以降を考えます。
の42桁目以降は、{00...001, 00...010, 00...011,...}
という感じで+1ずつ増やしていけばが最小となるので、の42桁目以降はの二進数表記となっているはずです。
従って、の最大は、
99999
の二進数表記 11000011010011111
の17桁
と
10000000000000000000000000000000000000000
の41桁
を連結させた数になります。
従って、58桁が考慮すべき最大桁数となると思います。
ABC249 参加記録
コンテスト中AC:A〜D
D - Index Trio
を変形すると、となります。
を固定すると、はの約数の組に限定されます。
よって、について、である約数についてのみ調べれば良く、各について、で全探索できます。
計算量は、の最大値を として、となり、間に合うか微妙なところですが大丈夫でした。
となる組が何通りあるかですが、
をに出現するの個数とすると、
となります。
これは、となる全てのに対して、となると組を作ることができるためです。
であるについて組を計算するわけですが、 である場合、組の順序を入れ替えると別の組になるので、2倍します。
逆に、の場合は入れ替えてできる組は同じなので、2倍しません。
提出コード Submission #31196140 - Monoxer Programming Contest 2022(AtCoder Beginner Contest 249)
なお、計算量を落とすことが可能です。
の全てについて、エラトステネスの篩と同じ方法で、試し割り不要で約数が記録された二次元配列を得ることが可能です。
計算量はとなり、二次元配列のサイズも同様にとなると考えられます。
組の計算にかかる計算量ですが、
上記に高度合成数の言及がありますが、ある整数以下の約数の個数が最大となるのが高度合成数です。
が全て以下の高度合成数であった場合が最悪となり、です。
上記によれば以下の高度合成数の約数の個数は160個なので、問題ないです。
Submission #31257209 - Monoxer Programming Contest 2022(AtCoder Beginner Contest 249)
ABC248 参加記録
コンテスト中AC:A〜D
D - Range Count Query
ウェーブレット行列が使えます。
ウェーブレット行列には以下の関数があります。
計算量は、今回の場合の要素の最大値をとって、です。
各クエリは、とすることで答えられます。
よって、すべてのクエリをで計算できます。
ウェーブレット行列の構築にかかるので、全体でです。
提出コード
E - K-colinear Line
の時は無限に存在するので、"Infinity"
です。
そうでない時、2点を決めれば直線を一意に定められるので2点を全探索します。
悩んだのが、同じ直線を2回以上使わないようにする処理です。
色々調べたことを書いておきます。
まず、2点を通る直線の式はググりました。
ので管理
式変形すると、
なので、
であり、これを管理します。
↓のtwitterで言及されていましたが、一意性を保つために正規化する必要があります。
熨斗袋 on Twitter: "格子点を通る直線は ax + by = c の形式で管理するのが楽なんじゃないかなと思う。"
熨斗袋 on Twitter: "gcd で割ったあと、min {(a, b, c), (-a, -b, -c)} で正規化"
にする
以下の2つは同じ式です。
これを同一視するため、として、でを割ります。符号を揃える
以下の2つは同じ式です。
これを同一視するため、(表現が正しいかわかりませんが、)符号を揃えます。
先程のツイートで言うところの、min({a,b,c}, {-a,-b,-c})を採用するのと同じだと思います。
下記実装では、構造体を作ってみました。
提出コード
ので管理
となります。小数での管理は誤差が心配なので、分数で管理します。
分数でも気をつける点があります。
- にする。すなわち、でを割る
- 符号を揃える。(正,正)なら(負,負)に、(正,負)にする。(これもmin({p,q},{-p,-q})で良さそうです)
また、この実装では、のパターン、すなわち、y軸に平行な直線の場合は例外処理が必要です。
として、y軸に平行な直線の座標を別に管理しておけば良いです。
これも構造体を作ってみました。
あと、公式解説と他の方の実装についても書いておきます。
探索済みの点対を管理
公式解説の方法です。
点とします。
flag[i][j]を点iと点jが探索済みならtrue、そうでなければfalseとします。
初め、全てfalseにします。
ある同一直線上にある全ての点の集合を、とします。に含まれるすべての点対に対して、
flag[i][j] = true
とします。
こうすることで、全探索の際にflag[i][j]=falseである点対だけ直線を求めればよいことになります。
基準となる2点を管理
他の方の実装を参考にした時によく見られました。
直線は2点によって一意に定めることができるので、先程の集合を何らかの基準でソートして、小さい方の2点を記録すること等で管理可能です。
点が直線上にあるかの判定
直線上であるかどうかの判定は、直線の式に代入していましたが、外積でいけるようです。
ARC138 参加記録
コンテスト中AC:A
A - Larger Score
一応、考察した内容ですが、あまり自信はないです。
番目までのから順番を保ったまま抜き出した部分列を、同様に番目以降の要素から得られる部分列をとします。
また、任意のを番目以降に移動させ、任意のを番目以内に移動させる操作を入れ替えと呼ぶことにします。
入れ替えに必要な操作回数
との入れ替えに必要な最小の操作回数は、を番目に移動させた後、を番目に移動させればよいので、が、がとすると、回となります。
複数個入れ替える場合に必要な操作回数
例えば、であると、であるを入れ替える場合を考えます。
この時、とを入れ替えてから、とを入れ替える必要があります。つまり、番目に近いもの同士から順に入れ替えます。
そうでない場合、操作回数はこれより増えます。
なぜなら、例えば、を先に番目に移動させると、は1つ前に出るため、必要な操作回数が1回増えます。
問題の条件を満たすのに必要な操作回数
まず、明らかにを満たすもの1組を入れ替えると達成可能です。
では、複数個入れ替えて最適になる場合があるか考えます。
今、以下と以上から個選び、それらが、以下の条件を満たすとします。
ここで、となる組を取り除いても、条件は満たされます。
取り除けるだけ取り除くと、結局、任意の、についてが成立します。
取り除いた後の個数をすると、前述したとおり、とを順に入れ替えしていくのが最適です。
ここで、とを交換した時点で問題文の条件を満たすので、結局1個だけの交換を考慮するだけでよくなります。
また、であったとします。この時、かつを満たすようなをの代わりにすると操作回数がより少なくなります。
結局、必要な最小回数の求め方は、について、とを入れ替える際に必要な交換回数を求め、その中の最小が答えとなります。但し、はかつを満たす中で最小のものです。
は、座標圧縮して、Segment Treeで計算しました。
提出コード
ABC243G Sqrt
自力AC
解をとします。
まず、以下の最大の整数は二分探索により、で得られます。ここでは、とします。
くらいの場合
が与えられた時に生成可能な数列の種類数
と定義すると、
と求められます。
ここで、の累積和をとっておけば、
と求められるので、の計算も含め、小さい方からDPテーブルをで計算できます。
なお、数列の項が1になった時点で1が延々と続くだけなので、初期値はです。
この時の解は、です。
くらいの場合
となります。
前述した通り、までのDPテーブルは計算できるので、解を得られます。
の場合
であり、
であるので、
とおけます。
これより、がとなる個数をとし、とすると、
とできます。
は以下でがとなるものの数です。
は、を満たすの個数として求められます。
とすれば、でDPテーブルを計算できます。
また、をの累積和とすると、
とおけます。
後は、の求め方ですが、
で求められます。