AtCoder Beginner Contest 349 F問題メモ

F - Subsequence LCM

問題

  • 長さ $N$ の数列 $A=(A_1,...,A_N)$ がある
  • ここから1つ以上の要素を選んで、その最大公約数がちょうど $M$ になるようにしたい
  • 選び方の個数を $\mod{998244353}$ で求めよ
    • $A$ には同じ値も含まれうるが、異なる位置から採用したものは別物として数える
  • $1 \le N \le 2 \times 10^5$
  • $1 \le M \le 10^{16}$

解法1

最大公約数を考えるには、まず $M$ を素因数分解する。
$M \le 10^{16}$ なので $O(\sqrt{M})$ の素因数分解はやや厳しく見えるが、演算が単純なのでできる。
不安なら確率的になるが高速なポラード・ロー法を使うこともできる。

たとえば $M=1176=2^{3}3^{1}7^{2}$ とできる場合、

  • $M$ を割り切ることができない $A_i$ は採用できないので、はじめから除いて考えてよい
  • $2^{3}$ を素因数に含む $A_i$ を最低1つ含む必要がある
  • $3^{1}$ を素因数に含む $A_i$ を最低1つ含む必要がある
  • $7^{2}$ を素因数に含む $A_i$ を最低1つ含む必要がある

これさえ満たせば、最小公倍数が $M$ になる。
すると、少し特殊なナップサック問題みたいに言い換えられる。

まず、$M$ の素因数の種類数を $K$(今回は $3$)として、各 $A_i$ をもとに長さ $K$ の bitflag $B_i$ を作る。

  • $A_i$ が $2^{3}$ を素因数に含むとき、$B_i$ の1の位に1を立てる
  • $A_i$ が $3^{1}$ を素因数に含むとき、$B_i$ の10の位に1を立てる
  • $A_i$ が $7^{2}$ を素因数に含むとき、$B_i$ の100の位に1を立てる

すると、「$B_i$ からいくつかを選んで、その bitwise-or が長さ $K$ の 111…1 となるような選び方の個数」を数えればよいことになる。

このとき、$2 \times 3 \times 5 \times 7 \times ...$ のように 素数を小さい方からかけると $14$ 個で $10^{16}$ を超えるので、素因数の種類数は最大でも $K \le 13$ となる。

$2^{13}=8192$ なので、普通にナップサックDPすると $O(N 2^K) \simeq 1.6 \times 10^9$ となりダメだが、
種類数が少ないことを利用して $B_i$ が同じものはまとめて遷移させると $O(4^K) \simeq 6.7 \times 10^7$ で求められる。

Python3

解法2

bitwise-or のところまでは解法1と同じだが、ゼータ変換・メビウス変換を使えばナップサックより高速に求められる。

Bi ごとに、個数をカウントした配列
  000  001  010  011  100  101  110  111
[   3    2    0    1    2    3    0    0 ]

↓ゼータ変換: 
    たとえば 110 の値は、Bi=000,010,100,110 のように110の部分集合であるBiの個数の和

  000  001  010  011  100  101  110  111
[   3    5    3    6    5   10    5   11 ]

↓2の冪乗にする:
    たとえば 110 の値は、bitwise-orが110の部分集合となるようなBiの選び方の個数

  000  001  010  011  100  101  110  111
[   8   32    8   64   32 1024   32 2048 ]

↓メビウス変換:
    たとえば 110 の値は、bitwise-orが "ちょうど" 110となるようなBiの選び方の個数

  000  001  010  011  100  101  110  111
[   8   24    0   32   24  968    0  992 ]

よって、この例の答えは 992 となる。

programming_algorithm/contest_history/atcoder/2024/0413_abc349.txt · 最終更新: 2024/04/23 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0