ユニークビジョンプログラミングコンテスト2025 秋(AtCoder Beginner Contest 425)E,F,G 問題メモ

E - Count Sequences 2

問題文

  • 正整数 $N$ および長さ $N$ の正整数列 $C=(C_1,C_2,\ldots,C_N)$ が与えられます。
  • 次の条件をすべて満たす正整数列の個数を与えられた正整数 $M$ で割った余りを求めてください。
    • 数列の要素はすべて $1$ 以上 $N$ 以下である。
    • 各 $i=1,2,\ldots,N$ に対し、$i$ は数列にちょうど $C_i$ 個含まれる。
  • $T$ 個のテストケースが与えられるので、それぞれについて答えを求めてください。
  • ただし、$M$ は $T$ 個すべてのテストケースにおいて共通です。

制約

  • $1\leq T\leq 10^5$
  • $2\leq M\leq 10^9$
  • $1\leq N$
  • $1\leq C_i$
  • $\sum_{i=1}^N C_i\leq 5000$
  • 全てのテストケースに対する $N$ の総和は $3\times 10^5$ 以下
  • 入力はすべて整数

解法1

$M$ がいつもの $998244353$ などであれば、なんてこと無い問題。

答えは高校数学でおなじみ、$\dfrac{(C_1+C_2+...+C_N)!}{C_1!C_2!...,C_N!}$ となるので 階乗のmod逆数を事前計算しておけばいい。

が、今回は $M$ が素数とは限らない。$x$ のmod逆数が計算できるのは、$M$ と $x$ が互いに素な場合に限られる。困った。

だが、答えの式は、($T=C_1+C_2+...+C_N$ として)

  • $T$ 個から $C_1$ 個の “1” を選ぶ
  • $T-C_1$ 個から $C_2$ 個の “2” を選ぶ

と、順次決めていくと考えれば、$N$ 個の二項係数の積で表せる。

$T \le 5000$ なので、その範囲の $\binom{n}{r}$ は、$O(T^2)$ で事前計算しておける。

解法2

解法1と比べて計算量も実装の簡単さも何も優れてないが、一応AC可能な解法。

$1!,2!,3!,...,5000!$ の素因数分解結果を、$F_n=\{2:○○, 3:○○, 5:○○,...\}$ という形で事前計算しておく。

$5000$ 以下の素数の個数を $\pi$ として $\pi=669$ より、 $669 \times 5000 \simeq 3.3 \times 10^6$ に比例する空間計算量で保存できる。

あとは、$F_T$ から、$F_{C_1},F_{C_2},...$ をキー毎に引いていけば、 最後に残ったものが答えを素因数分解したものになる。 $O(\pi N)$ で可能となる。

Python3

F - Inserting Process

問題文

  • 長さ $N$ の英小文字列 $T$ が与えられます。
  • 以下の条件をすべて満たす文字列の列 $s=(s_0,s_1,\ldots,s_N)$ の個数を $998244353$ で割った余りを出力してください。
    • $s_0$ は空文字列
    • $i=1,2,\ldots,N$ に対し、$s_{i}$ は $s_{i-1}$ の好きな位置(先頭や末尾でもよい)に好きな文字を $1$ 文字挿入することで得られる文字列
    • $s_N=T$

制約

  • $1\leq N\leq 22$
  • $N$ は整数
  • $T$ は長さ $N$ の英小文字列

解法

bitDP。
問題文の通りに「挿入」していくと考えるのは、常に完成形 $s_N=T$ を意識しないといけないところが面倒なので、 逆に $s_N=T$ から1文字ずつ「削除」することで $s=(s_N,s_{N-1},...,s_N)$ を作っていくことを考える。

  • $\mathrm{DP}[B]:=$ index の集合 $B$ の文字が残った状態から、全て空文字列にするまでのパターン数

この時、“abcccab” から $3,4,5$ 文字目のどれを削除しても、次にできる文字列は “abccab” となり、変わらなくなってしまう。
このような場合は一番先頭の文字のみを削除し、$4,5$ 文字目を削除できないとすると重複を防げる。

計算量は $O(N2^N)$。

Python3

G - Sum of Min of XOR

問題文

  • 正整数 $N,M$ と長さ $N$ の非負整数列 $A=(A_1,A_2,\ldots,A_N)$ が与えられます。
  • $\displaystyle \sum_{x=0}^{M-1} \min_{1\le i\le N} \left(x\oplus A_i \right)$ を求めてください。
  • ただし、 $x\oplus A_i$ は $x$ と $A_i$ のビット単位 $\mathrm{XOR}$ を表します。

制約

  • $1\le N\le 2\times 10^5$
  • $1\le M\le 10^9$
  • $0\le A_i \le 10^9$
  • 入力される値は全て整数

解法

Trieを考える。($M$ や $A_i$ がでかいので、陽に持つわけでは無い)

        ○
      /  \
    ○      ○      A=(2,4,5)
    /\      /\
  ○  ○  ○  ○    ●: Ai があるノード
  /\  /\  /\  /\
 ○○●○●●○○
  0 1 2 3 4 5 6 7

この状態で、たとえばわかりやすく $M=8$ とすると、木の真ん中で分けて、

  • $x=0~3$ に対しては、$A_i=2$ がXOR後の最小となる($4,5$ は $100_{(2)}$ のbitが立ってしまうので最小になり得ない)
  • $x=4~7$ に対しては、$A_i=4$ か $5$ がXOR後の最小となる($2$ は $100_{(2)}$ のbitが立ってしまうので最小になり得ない)

ということで、$A$ を $(2,)$ と $(4,5)$ に分けて、$x$ の値の範囲も2つに分けて、再帰的に調べていける。
関数 $f(r,A,b)$ を以下で定義する。

  • $f(r, A, b):=$
    • $\displaystyle \sum_{x=0}^{r-1} \min_{1\le i\le |A|} \left(x\oplus A_i \right)$ の値を求める関数で、
    • それを求めるにあたり、今考慮しているTrieの根の2つの子が $[0,b)$ と $[b,2b)$ の範囲を表す。
    • ただし、$A$ の値は全てこのTrie内 $[0,2b)$ にあり、$r \le 2b$ である前提とする。

$f(M,A,2^{29})$ の値が答えとなる。

$f$ の内部では、$A$ を2つに分割し、以下のようにする。

  • $B_0$: $b$ 未満の $A_i$ からなる数列
  • $B_1$: $b$ 以上の $A_i$ に対し、$b \oplus A_i$ からなる数列

これで左右を再帰的に調べて行きたいのだが、 ちょっと面倒な部分は、以下の処理をどうするかである。

  • $r$ が2のべき乗でなく中途半端な値だったとき
  • $B_0,B_1$ のいずれかが空のとき

$r$ の位置で場合分けする。

        ○
      /  \
    ○      ○
    /\      /\
  ○  ○  ○  ○
  /\  /\  /\  /\
 ○○●○●●○○
 (--①---](--②--]
  • ①の場合($1 \le r \le b$)
    • $|B_0| \ge 1$ の場合
      • $B_0$ にある要素だけで、$0 \le x \lt r$ を最小化できる。$f(M,B_0,b/2)$
    • $|B_0| = 0$ の場合
      • $B_1$ の要素を使うしかない。
      • $f(r,B_1,b/2) + rb$
      • この時点で、$0 \le x \lt r$ に対して $x \oplus A_i$ の $b$ の位置のbitが立つことが確定するため、$rb$ を加算する。
  • ②の場合($b \lt r \le 2b$)
    • $|B_0| \ge 1, |B_1| \ge 1$ の場合
      • $f(b,B_0,b/2)+f(r-b,B_1,b/2)$
    • $|B_0|=0$ の場合
      • $f(b,B_1,b/2)+f(r-b,B_1,b/2) + b^2$
      • この時点で、$0 \le x \lt b$ に対して $x \oplus A_i$ の $b$ の位置のbitが立つことが確定するため、$b^2$ を加算する。
    • $|B_1|=0$ の場合
      • $f(b,B_0,b/2)+f(r-b,B_0,b/2) + (r-b)b$
      • この時点で、$b \le x \lt r$ に対して $x \oplus A_i$ の $b$ の位置のbitが立つことが確定するため、$(r-b)b$ を加算する。

これで、再帰的に $O(N \log{\max(A)})$ で求めることができる。

Python3

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