Processing math: 100%

HHKBプログラミングコンテスト2025(AtCoder Beginner Contest 388)F,G 問題メモ

HHKBプログラミングコンテスト2025(AtCoder Beginner Contest 388)

GがEの上位互換でほぼ同じロジックを使えるので「問題ページに書いておいてほしかったなあ」とちょっと思った。
ABC386でもFがCの上位互換となっていて、こちらは問題ページにその旨の言及があったけど、なんで今回は無かったんだろうね。
ABC386は入力形式まで完全に一緒の問題だったからかな。

F - Dangerous Sugoroku

問題文

  • N 個のマスが 1 列に並んでおり、順に 1,2,,N の番号が付けられています。
  • M 個の整数組 (L1,R1),,(LM,RM) が与えられます。
  • マス j はある i に対して LijRi を満たすとき、またそのときに限り 悪いマス であると定めます。
  • マス 1 から以下の行動を繰り返すことでマス N に移動できるか判定してください。
    • 現在位置しているマスをマス x とする。以下の条件をすべて満たすような整数 i を選び、マス x+i に移動する。
      • AiBA 以上 B 以下から好きな目を選んで進める)
      • x+iNN にはちょうどで止まらなければならない)
      • マス x+i は悪いマスでない

制約

  • 2N1012
  • 0M2×104
  • 1AB20
  • 1<LiRi<N(1iM)
  • Ri<Li+1(1iM1)
  • 入力される値はすべて整数

解法

場合分けして考えることが多くて、漏れなく実装するのに注意を要する。

まず、Ri+1=Li+1 のような2つの禁止区間が連続しているものは、ややこしいので事前処理で1つにまとめておく。
以下、Ri+1<Li+1 とする。(禁止区間 ii+1 の間には必ず止まれるマスが存在する)

A,B の制約が小さい。
区間長 RiLi+1B なる i が1つでもあるなら、その禁止区間を飛び越せないので“No”である。
以下、各禁止区間の長さは B1 以下とする。

A=B の場合

毎回進めるマスが決まっている。
以下の2つを同時に満たせば到達できる。

  • N1A で割ったあまりが0である
  • (N1)/A=k として、1+A,1+2A,1+3A,...,1+(k1)A に悪いマスが存在しない

悪いマスは O(BM) 個以下なので、1つ1つについて 1+xA の形で表せないことを確認すればよい。

A<B の場合

N は馬鹿でかいので、「DP[i]:= マス i に到達可能」を O(N) などで解くのは無理。
ただし、禁止区間1つずつの長さは B119 で非常に短いと見なせる。
禁止区間は N マス全体からするとスカスカなので、禁止区間同士の間を一気に計算できればよい。

     Ri-1                                  Li     Ri
 X X X X o o o o o o o ..... o o o o o o o X X X X X o o o o o o o ...
禁止区間 `---P1--'               `---P2--' 禁止区間  `---P3--'

長さ B1 の区間 P1,P2,P3 を、禁止区間の前後にとる。
i 番目の禁止区間を越えるには、P2 のどこかに止まって、次に P3 のどこかに止まることになる。

P1 の中で、1から到達できるマスの集合を S1 とし、既知とする。
P2 の中で S1 から到達できるものを計算し、S2 とする。
さらに、P3 の中で S2 から悪い区間を飛び越して到達できるマスを計算し S3 とする。

S3 を次の S1 として、次の区間 i+1 の計算をする、ということを繰り返せばよい。 (最後に、ちょうど N に止まれるか?ということも、似たようにして確認できる)

S1S2 を計算したい。

ここで、実は P1P2 がある程度離れていれば P2 の全てに到達可能と見なせる。

悪いマスが存在しない場合、ある正整数 k に対し、今の位置から kAkB 先のマスはすべて到達可能である。
k 回の行動で全て A 進んだ場合は kA 進める。
その状態から、どれかの行動で1多く進んだことにすると、kA+1 進める。
これを繰り返して「k 回の行動で全て B 進み、計 kB 進んだ」状態にできるので、kAkB 進むことは全て可能である。

kB+1(k+1)A であれば、次の到達可能区間と連続し、以降の全てのマスに到達可能であるといえる。
式を整理すると kA1BA より、 少なくともざっくり kAA2400 以上離れていれば、必ず到達可能であると言える。

よって、(P2)(P1)+1400 なら全てに到達可能。
そうでない場合、t=1,2,...,400 に対して「何回かの行動で t 進むことは可能か?」を事前計算しておいて、 (出発点, 到着点) の組それぞれを O(|S1||P2|) かけて求めればよい。

S2S3 も、S2 からそれぞれ AB マス進んだ場合について O(|S2|B) かけて求められる。

ここで、いくつかのケースに注意しなければならない。

  • P3 と、次以降の禁止区間 Li+1Ri+1,Li+2Ri+2,... が被っている場合

S3 の計算後、先の禁止区間を全て除いておくなどする必要がある。

  Ri-1                        Li Ri
X X X o o o o o ... o o o o o X X X o X o X o
      `---P1--'     `---P2--'       `---P3--'
  • 複数の禁止区間を一気に飛び越す場合
        v計算中の禁止区間
o o X o X o X o o o ...
     |----P1---|
     |-| |----P3---|
     P2                計算中の禁止区間の前後のマスは使わず、
  a           b        aから一気にbへ飛ぶ場合

さっきの解法は1区間ずつ到達可能区間を引き継いでいくことを想定しているので、こういうのが上手く計算できない。

禁止区間後の P1,P3 は長さ B1 をフルで使うとし、禁止区間前の P2 は前の区間と被らないように定義する。

S1S2 を行う際、jS1 かつ Ri>j である要素については、直接的に S3 に入れると良い。

これで、O(MB2) (集合から集合を除く計算量によっては O(MB2logMB) など)で計算できる。

Python3

G - Simultaneous Kagamimochi 2

問題文

  • N 個の餅が小さいほうから順に並んでいます。
  • i 番目 (1iN) の餅の大きさは Ai です。
  • 2 つの餅 A,B の大きさをそれぞれ a,b としたとき、ab の半分以下であるとき、かつそのときに限り、餅 A を餅 B の上に乗せて鏡餅を 1 つ作ることができます。
  • 整数の 2 つ組が Q 個与えられます。
  • i 番目 (1iQ)2 つ組を (Li,Ri) として、次の問題をすべての i について解いてください。
    • Li 番目から Ri 番目までの RiLi+1 個の餅だけを使って、同時にいくつの鏡餅を作ることができるか求めてください。
    • より厳密には、以下ができるような最大の非負整数 K を求めてください。
      • Li 番目から Ri 番目までの RiLi+1 個の餅から 2K 個の餅を選んで K 個の 2 つ組に分け、それぞれの組について一方をもう一方の上に乗せることで鏡餅を K 個作る。

制約

  • 2N2×105
  • 1Ai109 (1iN)
  • AiAi+1 (1i<N)
  • 1Q2×105
  • 1Li<RiN (1iQ)
  • 入力はすべて整数

解法

ある区間に対する答えが k 個として、

  • a(上)になる方の餅は区間の先頭 k
  • b(下)になる方の餅は区間の末尾 k
  • 左から順番にペアにする

と考えてよい。

A: 4  5  6  7  8  9 10 11 12 13
   a           b
      a                       b    こんなペア群は
         a                 b

A: 4  5  6  7  8  9 10 11 12 13
   a                    b
      a                    b       こんなペア群と置き換えても必ず大丈夫
         a                    b

i から、「2AiAj になる最初の j」に対し、「ji」を事前計算し、C とする。
そのようなものが無い場合、Ni とする。
C の意味合いは「自身が上となる場合に、下に置ける餅は最低何個先でなければならないか」となる。

i: 1  2  3  4  5  6  7  8  9 10
A: 4  5  6  7  8  9 10 11 12 13
C: 4  5  6  7  6  5  4  3  2  1
                                 例: i=2, Ai=5 が上になる場合、
      |------------> o  o  o  o      下になる餅はCi=5個先の j=7, Aj=10 以降である必要がある

仮に以下の区間先頭 k=4 個を a 側として使おうと思うと、

A: 4  5  6  7  8  9 10 11 12 13
C: 4  5  6  7  6  5  4  3  2  1
   ~~~~~~~~~~

この中の C の最大値である「7」だけindexをずらせば、b として使えるindex群になる。
(逆に言うと、b として使うには、7 以上ずらす必要がある)
これが区間末尾をはみ出る場合、k ペア作るのは無理であることが分かる。

A: 4  5  6  7  8  9 10 11 12 13
C: 4  5  6  7  6  5  4  3  2  1
   ~~~~~~~~~~
   -------------------> ~~~~~~~~~~  この例では、区間をはみ出るので k=4 はNGとわかる。

A: 4  5  6  7  8  9 10 11 12 13
C: 4  5  6  7  6  5  4  3  2  1
   ~~~~~~~
   ----------------> ~~~~~~~        K=3 なら、6ずらしても区間内に収まるのでOKとわかる。

C を事前計算し Sparse Table などに載せれば、区間最大値を O(1) で取得できる。
つまり、クエリに対して k を決め打ったとき、それが可能かどうかが O(1) で判定できる。

各クエリに対して k を二分探索すればよい。O((N+Q)logN) で計算できる。

Python3

programming_algorithm/contest_history/atcoder/2025/0111_abc388.txt · 最終更新: 2025/01/14 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0