AtCoder Beginner Contest 461 E,F,G問題メモ

E - E-liter

問題文

  • $N$ 行 $N$ 列のグリッドがあります。はじめ、すべてのマスは白く塗られています。
  • $Q$ 回のクエリを与えられる順に処理してください。各クエリは以下のいずれかです。
    • タイプ 1: 整数 $R$ が与えられる。グリッドの上から $R$ 行目のマスをすべて黒く塗る。
    • タイプ 2: 整数 $C$ が与えられる。グリッドの左から $C$ 列目のマスをすべて白く塗る。
  • クエリを処理するたびに、処理が完了した時点でのグリッド内で黒く塗られているマスの個数を出力してください。

制約

  • $1 \leq N, Q \leq 3 \times 10^5$
  • タイプ 1 のクエリについて $1 \leq R \leq N$
  • タイプ 2 のクエリについて $1 \leq C \leq N$
  • 入力される値はすべて整数

解法

盤面の状況 $N^2$ を持つわけにはいかない。 「盤面をうまく復元できる情報」を見つけ、それを保持することで個数が特定できれば良い。

実は、最後の操作から遡って「タイプ1,2のどちらの操作を順に行ったかの列」(ただし、同じ行・列への操作は遡って最初に出てくる1回のみ含める)さえあれば、個数を特定できる。

タイプ1をB, タイプ2をWと表記

入力例 1 の 2 番目の操作まで
最後の操作から                 ###    B は、1個あたり N (=3) 個塗れる。
  タイプ   B  B                ...    この例ではBが2つあるので、6個塗れる。
  対象列   3  1                ###

入力例 1 の 3 番目の操作まで
最後の操作から                 #.#    B は、自身より前に W があると、
  タイプ   W  B  B             ...    その個数だけ、塗れる数が N から少なくなる。
  対象列   2  3  1             #.#    この例では最初のWによって
                                      Bの塗れる数が1つ当たり2個になっている。

入力例 1 の 4 番目の操作まで
最後の操作から                 ###    過去に操作済みの行・列に操作した場合は、
  タイプ   B  W  B             ...    既存のを取り除き、先頭に持ってくる。
  対象列   1  2  3             #.#    (B,1)は先頭に持ってきたことで
                                      W の影響がなくなり、再び3マス塗れるようになる。

このような状態を管理しつつ、全体の黒マスの数の差分計算ができればよい。

例えば、以下の状態を持つと管理できる。

  • $S_B$: クエリ番号 $q$ をindexとした一点更新区間和取得のセグ木。指定したクエリ範囲の有効な B 操作の個数を取得できる
  • $S_W$: クエリ番号 $q$ をindexとした一点更新区間和取得のセグ木。指定したクエリ範囲の有効な W 操作の個数を取得できる
  • $A[t,i]:=$ タイプ $t$ の、$i$ 行(列)目に対する操作で、最後に行われたもののクエリ番号(無い場合は-1など)
  • $ans:=$ 現在の黒の個数

これで、「過去の操作(あれば)を無かったことにすると、黒の個数はどれだけ増減するか」「今の操作で黒の個数はどれだけ増減するか」がわかる。

$q$ 個目のクエリにおいて、

  • B 操作の場合
    • 過去に同じ行への操作がある場合、$p$ 個目のクエリとして
      • その操作は、$N-$($[p,q)$ にある W 操作の個数)分だけ答えに寄与していた。
      • $S_W$ から求め、$ans$ を減らす。
      • $S_B[p]$ を $0$ にする。
    • その後、$N$ だけ $ans$ を増やす。
    • $S_B[q]$ に $1$ をセットする。
  • W 操作の場合
    • 過去に同じ列への操作がある場合、$p$ 個目のクエリとして
      • その操作は $[0,p)$ にある B 操作の個数だけ答えを減らしていた。
      • $S_B$ から求め、$ans$ を増やす。
      • $S_W[p]$ を $0$ にする。
    • その後、$[0,q)$ にある B 操作の個数だけ黒が減る。$S_B$ から求め、$ans$ を減らす。
    • $S_W[q]$ に $1$ をセットする。

としていくとよい。

Python3

F - Total Product is N

問題文

  • 正整数 $N$ が与えられます。
  • 以下の条件をすべて満たす空でない正整数列 $A$ を良い数列と呼ぶことにします。
    • $A$ の各要素は相異なる
    • $A$ の要素の総積は $N$ に等しい
  • 数列のスコアを、その数列の要素の総和で定義します。
  • すべての良い数列のスコアの合計を $998244353$ で割った余りを求めてください。

制約

  • $1 \leq N \leq 10^{10}$
  • 入力される値は整数

解法

ちょっとややこしいナップサックDPのようなもの。

まず、$A$ には $N$ の約数しか採用できない。今回の制約で約数の個数の上限は、$N=6983776800$ 等のとき、$2304$ 個。

これらについての採用する/しないを決定するので、ナップサックDPと似た発想となる。

  • $\mathrm{DP}[i,p,c]:=i$ 個目の約数までを考慮して、採用した要素の総積が $p$ で、個数が $c$ 個の時の(状態数, 総和の総和)

個数 $c$ も添字にする必要がある。
基本的に、ナップサックDPで求めるのは採用する「集合」に対しての集計値であって、その中の順番は区別されない。 しかし今回は、集合として同じ $A$ でも並べ方が異なるものは区別しなければならない。
$A$ に同じものが含まれないので、長さ $c$ のものの並べ替え方は一律 $c!$ 通りと計算できる。 総積に加え、長さ別に状態を分けてDPすると十分となる。

“総和の総和” は、「暫定で $A$ に採用した値の総和」を、$(p,c)$ が同じ全ての状態で総和を取ったものを意味する。 ただし上述の通り、並べ替えただけのものは最後に $c!$ 倍すればよいので、採用した値の集合が同じものは1回のみ数えるものとする。

$p$ は $N$ の約数の値しか取りえない。また、$c$ の上限もそこまで上限が大きくない(実際は $14$ 程度)ことがわかるので、DPの計算量の上限は $14 \times 2304^2$ に比例する量であり、十分高速にDPを埋められる。

Python3

G - Graph Problem 2026

問題文

  • $N$ 頂点 $M$ 辺の単純無向グラフがあります。
  • 各頂点には $1$ から $N$ の番号が、各辺には $1$ から $M$ の番号が付いており、辺 $i$ は頂点 $u_i$ と $v_i$ を結んでいます。
  • 以下の条件を満たすように、各頂点 $j$ に $2026$ 以下の非負整数の重み $W_j$ を割り当てます。
    • 各辺 $i$ について、$W_{u_i}+W_{v_i} \leq 2026$
  • すべての頂点の重みの合計(すなわち $\sum_{j=1}^{N}{W_j}$)としてあり得る値の最大値を求めてください。

制約

  • $1 \leq N \leq 5 \times 10^4$
  • $0 \leq M \leq 5 \times 10^4$
  • $1 \leq u_i \lt v_i \leq N$
  • $(u_1,v_1),(u_2,v_2),\dots,(u_M,v_M)$ は相異なる
  • 入力される値はすべて整数

解法

答えは何となく、連結成分毎に以下の2通りのどちらかになりそう?

  • (a) 最大独立集合(どの2頂点の間にも辺が無い頂点集合の中で最大のもの)に2026、他に0を割り当てる
  • (b) 全ての頂点に1013を割り当てる

…と直感的に思うが、結果的にこれは誤っている。

誤りのケース
○○○    9頂点の完全グラフのうち1頂点①に、別の8頂点がそれぞれ直接繋がっている
○○○     (a) 最大独立集合に2026を割り当てる: 9頂点なので 18234
○①○     (b) 全てに1013を割り当てる: 17221
 /|\\    (c) 完全グラフの①以外の8頂点に1013、①は0、残り8頂点は2026: 24312
∞∞∞∞  双方のいいとこ取りをした(c)の割り当て方が、最も大きくなる。

もし直感が正しければ、最大独立集合のサイズがわかれば良かったのだが、 そもそも最大独立集合のサイズもNP完全なので、今回の制約では解けない。

\(^o^)/

想定解法は以下の通り。

最大独立集合は、線形計画問題に落とし込むと、以下のようになる。

  • 各頂点 $i$ に、$x_i \in \{0,1\}$ の整数の重み $x_i$ を割り当てる。
  • 目的:
    • $\sum_ix_i$ を最大化するような $x_1,...,x_N$ の値の割り当て方を求める
  • 制約:
    • 全ての辺 $(u_j,v_j)$ について、$x_{uj}+x_{vj} \le 1$

これの、$x_i$ に対する整数条件を緩和(LP緩和)すると、以下のようになる。むしろこちらの方が元の問題に近い。

  • 各頂点 $i$ に、$0 \le x_i \le 1$ の実数の重み $x_i$ を割り当てる。
  • 目的と制約は同じ

そしてこの問題は、「半整数解」を持つことが知られている。 つまり、「全ての $x_i$ が $\{0,0.5,1\}$ のいずれかを取るような解が必ず存在する」ことが言える。

略証

元の問題に戻ると、そのまま「$($ 半整数解での $\sum x_i) \times 2026$」が答えとなる。
$2026$ が偶数であることで、各頂点の重みは $\{0,1013,2026\}$ で整数値が保証される。(2026がもし奇数だったら解けない)

この半整数解は、以下のように解ける。

  • 頂点を倍加し、$A_1,...,A_N,B_1,...,B_N$ とする。
  • 元の辺 $(u,v)$ に対し、$(A_u,B_v)$、$(A_v,B_u)$ の両方に辺を張ることにすると、これは二部グラフとなる。
  • 二部グラフの最大独立集合なら最大流に帰着させて解くことができる。
  • 二部グラフの最大独立集合のサイズ/2 が 元の問題のLP緩和解の $\sum x_i$ となる。

これで求まる略証

Python3

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