AtCoder Regular Contest++ 216 A,B,C問題メモ

AtCoder Regular Contest++ 216

ぷらぷらが始まった(ARC Div.1に相当する新名称)。

A - Reversi 3

問題文

  • 01 からなる長さ $N$ の文字列 $A,B$ が与えられます.$A$ の $i$ 文字目を $A_i$ とします.
  • あなたは以下の操作を $0$ 回以上好きな回数行うことができます.
    • $A_{i-1}=A_{i+1}$ を満たす整数 $i\ (2\leq i\leq N-1)$ を選び,$A_i$ を反転する(1 ならば 0 に,0 ならば 1 にする).
  • 操作を繰り返すことで $A$ を $B$ に一致させることができるか判定し,可能ならば一致させるために必要な操作回数の最小値を求めてください.
  • $T$ 個のテストケースが与えられるので,それぞれについて答えを求めてください.

制約

  • $1\leq T\leq 2\times 10^5$
  • $3\leq N\leq 10^6$
  • $A,B$ は 01 からなる長さ $N$ の文字列
  • $T,N$ は整数
  • 全てのテストケースに対する $N$ の総和は $10^6$ 以下

解法

まず、端の要素は変えられないので、$A_1 \neq B_1$ または $A_N \neq B_N$ の場合、不可能である。以下、同じとする。

(制約からも何となくそんな気がするとおり) 貪欲っぽく左から合わせていく解法が成り立つ。
ただし、「一致させるためには $i$ で操作しないといけないが、 今のままでは操作できないので、$i$ より右で一旦操作し、 遡ってきて $i$ を操作できる状態にする」必要がある場合もある。

A  0 1 1 0 0 1 0
B  0 0 . . . . .
     ^------------- ここを反転させたいが、両隣が異なるので操作できない
       ^ ^ ^------- ここらも同じく無理
             v----- ここでやっと反転できる
   0 1 1 0 0 0 0
           v        一旦反転させたら、反転させられなかった箇所は
   0 1 1 0 1 0 0    順次左に1個ずつ反転させていける
         v
   0 1 1 1 1 0 0
       v
   0 1 0 1 1 0 0
     v
   0 0 0 1 1 0 0
        ↕          この時、最初のAから、
A  0 1 1 0 0 1 0    反転させたかった箇所 ~ はじめて反転できる箇所 が
     ~ ~ ~ ~ ~      まるっと反転した形となる。

その際、$A,B$ のままでは(解けなくはないが) どこから波及させられるか扱いづらいので、扱いやすい形に変換する。

以下のように $E,F$ を作る。

  • $C=(C_1,...,C_{N-1}),D=(D_1,...,D_{N-1})$ を、それぞれ $A,B$ の隣接要素のXORとする。
  • $E=(E_1,...,E_{N})$ を、$(0,C_1,...,C_{N-1},0)$ の隣接要素のXORとする。
  • $F=(F_1,...,F_{N})$ を、$(0,D_1,...,D_{N-1},0)$ の隣接要素のXORとする。

逆の操作をすれば $E,F$ は $A,B$ に一意に復元できるので、$E$ を $F$ に一致させればよい。

操作は $E$ 上では以下のようになる。

  • $E_i=0$ である $i$($2 \le i \le N-1$)を選び、両隣の要素 $E_{i-1},E_{i+1}$ を反転させる

$i=1,2,...,N-2$ の順に、$E_i \neq F_i$ なら、$i+1$ に操作をしなければならない。

i     1 2 3 4 5 6 7 8 ...
A     0 1 1 0 0 1 0 0
B     0 0 . . . . . .
C  (0) 1 0 1 0 1 1 0
D  (0) 0 . . . . . .
E     1 1 1 1 1 0 1   ...
F     0 . . . . . .   ...

上例では、まず早速 $i=1$ の時、$E_1 \neq F_1$ のため $E_{i+1}$ に操作する必要があるが、$E_2=1$ なので今のままでは操作できない。

$j=6$ で操作可能になるので、左に派生させていくと、できるようになる。

      i         j
E     1 1 1 1 1 0 1
                v
      1 1 1 1 0 0 0
              v
      1 1 1 0 0 1 0
            v
      1 1 0 0 1 1 0
          v
      1 0 0 1 1 1 0
        v
      0 0 1 1 1 1 0

その際、操作回数は $j-i$ 回必要で、元のEからは、以下のように変化する。

  • $i+1=j$(操作したい $i+1$ が、そのまま $E_{i+1}=0$ だった)場合、
    • $i-1,i+1$ が反転する
  • $i \lt j$ の場合、
    • $j$ は $0→1$
    • $i$ は $1→0$
    • $i-1,j+1$ が反転する

この変化により、 $i+2,...,j$ は全て $1$ となるため、次に例えば $i+1$ を反転させたい場合、$i+2$ 以降で $0$ が出現するのは必ず $j+1$ 以降となる。

$i$ を進めていくのに伴い、$j$ のポインタも進めていけば、$O(N)$ で答えが求められる。

Python3

B - Range Mex Sum

問題文

  • 正整数 $N$ および整数列 $A=(A_1,A_2,\ldots,A_N)$ が与えられます.$A_i$ は $-1$ 以上 $N-1$ 以下であり,$1\leq i\lt j\leq N$ に対し,$A_i\neq -1$ かつ $A_j\neq -1$ ならば $A_i\neq A_j$ です.
  • 次のクエリを $Q$ 回解いてください.
    • 整数 $l,r\ (1\leq l\leq r\leq N)$ が与えられる.
    • $(0,1,\ldots,N-1)$ の順列 $P=(P_1,P_2,\ldots,P_N)$ であって,$A_i\neq -1\implies P_i=A_i$ を満たすようなもの全てに対する $\mathrm{mex}(\lbrace P_l,P_{l+1}, \ldots,P_r\rbrace)$ の総和を $998244353$ で割った余りを求めよ.

制約

  • $1\leq N\leq 5000$
  • $1\leq Q\leq 5\times 10^5$
  • $-1\leq A_i\leq N-1$
  • $1\leq i\lt j\leq N$ に対し,$A_i\neq -1$ かつ $A_j\neq -1$ ならば $A_i\neq A_j$
  • 各クエリにおいて,$1\leq l\leq r\leq N$
  • 入力は全て整数

解法

$A$ にある $-1$ の個数を $m$ とする。また、$A$ に存在しない $0~N-1$ の値を小さい順に $B_1,B_2,...,B_m$ とする。

全ての場合の総和を直接考えるより、期待値(MEXの値×そのMEXになる確率)を考えた方がわかりやすい。 期待値に全体の数 $m!$ をかければ全ての場合の総和となる。

ある1クエリに答えることを考える。以下の2要素によって決まる。

  • $x$: その区間内にある $-1$ の個数
  • $k$: その区間内に無い、$-1$ でない最小の $A_i$ の値(存在しない場合は $k=N$)
例
A  _ _ 5 _ 1 3 _ _ _ 7    m=6  B=(0,2,4,6,8,9)
        [l-------r]       x=3  k=5
  • $B_1=0$ になるのは、$B_1$ が区間外に配置されたとき
    • 確率 $\frac{m-x}{m}$
  • $B_2=2$ になるのは、$B_1$ が区間内、$B_2$ が区間外に配置されたとき
    • 確率 $\frac{x}{m} \times \frac{m-x}{m-1}$
  • $B_3=4$ になるのは、$B_1,B_2$ が区間内、$B_3$ が区間外に配置されたとき
    • 確率 $\frac{x}{m} \times \frac{x-1}{m-1} \times \frac{m-x}{m-2}$
  • $B_4 = 6 \gt k = 5$ なので、これ以上は必ず $k$ の方がMEXになる。
    • $B_1,B_2,B_3$ が区間内に配置されたとき。
    • 確率 $\frac{x}{m} \times \frac{x-1}{m-1} \times \frac{x-2}{m-2}$
別の例
A  _ _ 5 _ 1 3 _ 4 _ 7    m=5  B=(0,2,6,8,9)
      [l---------r]       x=2  k=7
  • $B_1=0$ になるのは、$B_1$ が区間外に配置されたとき
    • 確率 $\frac{m-x}{m}$
  • $B_2=2$ になるのは、$B_1$ が区間内、$B_2$ が区間外に配置されたとき
    • 確率 $\frac{x}{m} \times \frac{m-x}{m-1}$
  • これで区間内の $-1$ が全て埋まるので、これ以外は必ず $\min(k,B_3)$ になる。
    • 確率 $\frac{x}{m} \times \frac{x-1}{m-1}$

$B_i$($i=1,2,3,...$)がMEXになる確率は、小さい方から順に求めていける。 どこかで $k$ によって打ち切られるか、$x$ が全て埋まって次の $B_{x+1}$ が確定でMEXになる。

「$k$ による打ち切り」の発生有無とその値はクエリによって異なるが、それ以外は $x$ にのみ依存する。
言い換えると、$x$ が同じクエリは、打ち切りの発生までは前計算結果を共有できる。

$k$ を無視して、以下を計算しておく。

  • $C'[x][i]:=$ 区間内 $-1$ が $x$ 個の時、MEXが $B_i$ になる確率
  • $D'[x][i]:=$ 区間内 $-1$ が $x$ 個の時、MEXが $B_i$ になる期待値(確率 $\times B_i$)
  • $C:=C'$ を $i$ について累積和を取ったもの
  • $D:=D'$ を $i$ について累積和を取ったもの

各 $x$ に対し、有効な $i$ は $1~x+1$ なので、その範囲を前計算しておく。$O(N^2)$ で計算できる。

すると、$k$ があるときの答えは、

  • $B$ の中で $k$ を超えない最大を $B_i$ とする。
  • $i=0$($k \lt B_1$)の時、MEXは常に $k$
  • $x \ge i$ の時、区間内に $i$ 個置いた時点で $k$ が必ず次のMEXになる。
  • $x \lt i$ の時、区間内に $x$ 個置いた時点で $B_{x+1}$ が必ず次のMEXになる。

「区間内に $y$ 個置いた時点で $z$ が必ず次のMEXになる」というクエリでは、以下が期待値となる。

  • $D[x][y] + (1-C[x][y]) \times z$

$x$ や $k$ を求める際にセグメント木等を使うと1クエリ $O(\log{N})$、累積min・累積和などを使えば $O(1)$ で求められる。 $B,k$ から $i$ を求めるのは、二分探索で $O(\log{N})$、各 $k$ の値に対する $i$ を前計算しておけば $O(1)$ で答えられる。

全体 $O(N^2 + Q)$ または $O(N^2 + Q\log{N})$ となる。

Python3

C - Count Power of 2

問題文

  • 長さ $N$ の非負整数列 $A=(A_1,A_2,\ldots,A_N)$ が与えられます.
  • $2^{A_l}+2^{A_{l+1}}+\dots+2^{A_r}$ が $2$ べきとなるような整数の組 $(l, r)\ (1\leq l\leq r\leq N)$ の個数を求めてください.ただし,$2$ べきとはある非負整数 $k$ を用いて $2^k$ と表される数を言います.

制約

  • $1\leq N\leq 2\times 10^5$
  • $0\leq A_i\leq 2\times 10^5$
  • 入力は全て整数

解法

$A_i$ を $A_i$ のまま扱い、2個セットで1ランクアップするスライムみたいなやつと考える方向性もあり得そうだが、、、
$(0,0,1,2,2,2,5)$ のように、全然2べきにならない集合に $4$ を加えた途端、急に2べきが成立することがあるように、 条件を満たす区間に連続性がないのがどうにも上手く扱えない。

ハッシュ化して解く。

適当な大きい素数 $P$ で各 $2^{A_i} \mod{P}$ を計算し、その累積和 $Acc$ を取っておくと、

  • $l,r,x$ に対して、区間 $[l,r)$ の和は $\mod{P}$ 上で $2^x$ に等しいか?

はすぐに計算できる。
問題は、以下の2つ。

  • ①$l,r$ の組が $O(N^2)$、$x$ の候補が $A_{\max}+\log{N}$ くらいあって、全然間に合わない
  • ②ハッシュ衝突の可能性

①探索範囲を絞る

まず $x$ の範囲を絞る。

区間 $[l,r)$ の最大値を $m$ とする。するとその区間の総和が $2^x$ となりうるような $x$ は、

  • 最小値: $m$
  • 最大値: $m+\log_2{N}$($2^m$ 以下の数を高々 $N$ 個集めて $2^{m+\log_2{N}}$ より大きくなることは無い)

よって $x$ は $\log{N}$ 程度の候補に絞られる。

最大値が $m$ となるような区間は、Cartesian Tree を構築して、分割統治をしていくことで求めていける。
$m$ が大きい方から、左・右をどこまで伸ばせるか、というのが分割されて狭まっていく。

A   1  2  5  1  3  2  6  1  4  0  0
             
  |<------------------6------------>|
  |<------5--------->| |<---4------>|
  |<---2>| |<---3--->| |<1>| |<0--->|
  |<1>|    |<1>| |<2>|          |<0>|

今着目中の、最大値が $m$ となる区間を $[L,R)$ とする。また、$m$ の位置を $k$ とする。

   L           k         R
  |<-----------6------->|

$x=m,m+1,...,m+20$ くらいの範囲を全探索する。
$L \le l \le k$、$k+1 \le r \le R$ を満たす $l,r$ の中で、$Acc[l]+2^x=Acc[r]$ となるような組の個数を求めたい。

さらに $l$ を全探索することにする。以下の前計算により、

  • $Pos[a]=[i_1,i_2,...]$
    • 累積和 $Acc$ の中で、$a$ が出現するindexリスト

$r$ としてあり得る数は、$Pos[Acc[l]+2^x]$ の中で $k+1~R$ の範囲の数なので、二分探索することで求められる。
(または、累積和の中で同じ数が出現する回数は十分に少ないとの見積もりの上、$Pos[Acc[l]+2^x]$ 内を全走査してもいい)

ただし、「決まって $l$ の方を全探索し、相方の $r$ の候補を探す」というアルゴリズムは、 例えば以下のような $A$ で $l$ の全探索が $O(N^2)$ となり、TLEとなる。

A   0  1  2  3  4  5  6

  |<------------------6>|
  |<---------------5>|
  |<------------4>|
  ...

$l$ 側と $r$ 側、候補の少ない方を全探索することで、探索数が全体を通して $O(N)$ に収まる。

②ハッシュ衝突防止

ハッシュは、各区間 $[l,r)$ および $x=0~A_{\max}+20$ くらいの範囲につき、 「その区間の総和 $\pm 2^x$」が区別できる必要がある。単一の $P$ で mod を取っただけでは普通に衝突する。

複数のMODを使うことで、これを防ぐ。つまり、

  • $Pos[(x_1,x_2,x_3)]=[i_1,i_2,...]$
    • 3種類の素数 $P_1,P_2,P_3$ に対し、
      • $P_1$ でmodを取った累積和が $x_1$
      • $P_2$ でmodを取った累積和が $x_2$
      • $P_3$ でmodを取った累積和が $x_3$
    • …となるような index のリスト

のようにすると、衝突確率を減らせる。(この場合の厳密な確率計算はできてないが)

Python3

programming_algorithm/contest_history/atcoder/2026/0322_arc216.txt · 最終更新: by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0