AtCoder Regular Contest 218 A,B,C問題メモ

A - Many Sets

問題文

  • 長さ $M$ の正整数列が $N$ 個与えられます。$i$ 個目の正整数列は $A_i=(A_{i,1},A_{i,2},\dots,A_{i,M})$ です。
  • これら $N$ 個の正整数列から $1$ 個ずつ要素を選ぶ方法は $M^N$ 通りあります。
  • その全てに対する「選んだ要素に含まれる整数の種類数」の総和を $998244353$ で割った余りを求めてください。

制約

  • $1 \le N,M \le 500$
  • $1 \le A_{i,j} \le NM$
  • 入力は全て整数

解法

以下のDPを定義する。ただし、各数列から $1$ 個ずつ要素を選ぶ際は一様ランダムに選ばれるものとする。

  • $\mathrm{DP}[i,a]:=i$ 番目の数列までで、要素 $a$ が1回以上選ばれている確率

初期値 $\mathrm{DP}[0,*]$ は全て $0$ とする。

$i$ 番目の数列に $a$ が $c$ 個出現しているとすると、

  • $\mathrm{DP}[i,a]+=(1-\mathrm{DP}[i-1,a]) \times \dfrac{c}{M}$

のように更新できる。 つまり、($i-1$ までで $a$ が選ばれていない確率)×($i$ で $a$ が選ばれる確率)だけ、$a$ の選ばれている確率が増える。

$i$ 番目の数列に出現しない要素に変化はないので、出現する箇所のみ更新すればよい。
また、実装の上では $i$ の次元は省略し、$\mathrm{DP}'[a]$ を直接更新していってよい。

最終的に期待値は $\sum_a \mathrm{DP}[N,a]$ となり、問題の答えはそれに $M^N$ をかけたものとなる。

計算量は $O(NM)$

Python3

B - All Minus

問題文

  • 黒板に $N$ 個の非負整数 $A_1,A_2,\dots,A_N$ が書かれています。
  • Alice と Bob がゲームをします。Alice から始めて以下の操作を交互に行い、黒板に書かれている整数を $0$ 個にした方が勝ちです。
    • 操作を行う時点で黒板に書かれている最小の非負整数を $m$ とする。
      • $m \gt 0$ のとき、$1$ 以上 $m$ 以下の正整数 $x$ を選ぶ。黒板に書かれている全ての整数をそれぞれ今の値から $x$ 引いた数に書き換える。
      • $m = 0$ のとき、黒板に書かれている $0$ のうち、$1$ 個以上を削除する。
  • 両者が勝つために最善な行動をしたとき、勝つのがどちらか判定してください。
  • $T$ 個のテストケースが与えられるので、それぞれについて解いてください。

制約

  • $1 \le T \le 2 \times 10^5$
  • $1 \le N \le 2 \times 10^5$
  • $0 \le A_i \le 10^9$
  • 全てのテストケースに対する $N$ の総和は $2 \times 10^5$ 以下
  • 入力は全て整数

解法

$A$ は昇順にソート済みとする。

棒グラフを描いてみると、ゲームで取れる行動の良い言い換えが見える。

A = (1, 2, 4, 4, 7)

→┝┓
  ├┻┓
  ├─┻━┓
  ├───┨
  ├───┻━━┓
  ├──────┛
                ↓

棒グラフの左上(矢印→の先)にコマを置き、以下のルールに沿って交互に動かし、右下↓に到達させた方が勝ちとなる。

  • 太く示した、棒の上と右の線上のみ動ける
  • 1回の移動の中で方向転換禁止
  • 必ず1は進む

方向転換まで残り距離 $1$ なら、動かし方に選択の余地がない。
$A=(1,2,3,4,5,6)$ のような階段だと、両者とも選択の余地はないまま、交互に動かすだけになる。

しかし、$A=(1,2,4,4,7)$ のように、ヨコやタテに距離 $2$ 以上が発生すると、その手番のプレイヤーは

  • その距離を全て消費しきる
  • その距離を $1$ だけ残して消費しきる

を自由に選択することで、攻守(?)を交替できる。

つまり、「次に出現する、距離 $2$ 以上の辺」があるなら再びそれを自分の手番にするように、 ないなら最後に自分が勝つように選択できる。

最初からシミュレーションして、

  • 最初に距離 $2$ 以上の辺に遭遇した手番のプレイヤーが勝利
  • 最後まで1つも無いなら、動かし方は一意なのでシミュレーションの結果が答え

$A$ が $0$ を含む場合はAliceは初手↓方向に動かすので注意。

Python3

C - Amidakuji

問題文

  • この問題はインタラクティブな問題です。
  • 正整数 $N$ が与えられます。
  • 正整数 $m$ と $m$ 個の $(1,2,\dots,N)$ の順列を好きに決め、出力してください。
    • このうち $i$ 個目の順列を $P_i=(P_{i,1},P_{i,2},\dots,P_{i,N})$ とします。
    • これは「$k→P_{i,k}$ という置換」を表すとし、「置換 $i$」と呼ぶこととします。
  • その後、$(1,2,\dots,N)$ の順列 $Q=(Q_1,Q_2,\dots,Q_N)$ が与えられます。
  • 以下の条件を全て満たすような正整数列 $A=(A_1,A_2,\dots,A_k)$ を出力してください。
    • $0 \le k \le 2N^2$
    • $A$ の要素は全て $1$ 以上 $m$ 以下
    • 数列 $R=(1,2,\dots,N)$ に対して、$i = 1,2,\dots,k$ の順に置換 $A_i$ を行うと $R = Q$ となる。
  • 上記の問題を $Q$ によらずに正解する上での最小の $m$ を $m_{\min}$ とします。あなたの出力する $m$ は $m_{\min}$ でなければなりません。

制約

  • $3 \le N \le 500$
  • $Q$ は $(1,2,\dots,N)$ の順列
  • 入力は全て整数

解法

少し問題がややこしい。$Q$ が最初に分かってしまうと自明すぎるので、最初に使う置換を宣言させられる。

使う置換の決定

(言うて600点問題というメタ読みも含め) そこまで複雑な構築にはならず、ある程度 $m$ 個の数列は規則的なものになるはずと当たりを付ける。

$m$ をどこまで減らせるか考えたときに、 はじめ「$m=N-1$ とし、$i=1,2,...,N-1$ につき $i$ と $i+1$ のみをswapするもの」が思い浮かぶ。

だが、それを使った構築を考えだすと、よりよい $m=2$ が必ず達成可能であることに気付く。

  1. $1~N-1$ をローリングし、$N$ はそのまま動かない置換
  2. $N-1$ と $N$ をswapし、他は動かない置換

要は、$1~N-1$ をループ式のベルトコンベアと見なし、 要素を $N$ にストックしては好きな位置に戻すことを繰り返して、任意の並びを作れる。

1つの要素を好きな位置に持っていくために

  • 最大 $N-1$ 回のローリングで、ターゲットを $N-1$ に持ってくる
  • swapして $N$ にストック
  • 最大 $N-1$ 回のローリングで、挿入したい位置に持ってくる
  • swap

計 $2N$ で達成可能となる。全体で約 $2N^2$ と見積もれ、まさに問題の条件通りなので確信度が高まる。

構築

まずは考えやすくするため、「$(1,2,...,N)→Q$ にする置換列」と「$S→(1,2,...,N)$ にする置換列」が 同じになる $S$ を特定し、後者で考える。$S$ は、$Q$ の逆順列(indexと値が逆転したもの)とすればよい。

その後、$i=2,3,...,N-1$ の順に、要素 $i$ を $i-1$ の直後に持ってこさせる。つまり、

  • $i=2,3,...,N-1$ の順に、
    • 要素 $i$ がストック(位置 $N$)になければ、
      • 位置 $N-1$ までローリングする
      • swapする
    • 要素 $i-1$ を位置 $N-2$ までローリングする
    • swapする
  • 最後に要素 $1$ が位置 $1$ に来るまでローリングする

とすることで構築できる。各操作は、実際に数列をその通りにシミュレーションして確かめて $O(N^3)$ なので十分間に合う。

なお、必要は無いが、工夫すれば最悪操作回数を約 $2N^2→N^2$ に減らせはする。
最初に $1$ の位置から $2~N-1$ の相対的な挿入位置は決められるので、$i=2,3,...$ の順ではなく、 現在ストックに入った順に挿入(その際のswapによって新たにストックに入った要素をまた挿入……)していくと、可能となる。

Python3

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