AtCoder NoviStepsを埋めてみる(8) エラトステネスの篩の続きです。今回もエラトステネスの篩です。難しめの問題に挑戦します。

030 – K Factors(★5)

030 – K Factors(★5)

問題の概要

2 以上 N 以下の整数のうち、K 種類以上の素因数を持つものの個数を求めよ。

長さ N + 1 の配列を定義し、素因数 x をもつのであれば(素因数 x の倍数であれば)インクリメントすることで素因数の種類数を記録していくことができます。そのなかから値が K 以上のものを数えればよいです。

E – Ringo’s Favorite Numbers 3

E – Ringo’s Favorite Numbers 3

問題の概要

素因数がちょうど 2 種類であり、その各素因数でその数が割り切れる回数は偶数回であるものを 400 number と定義する。
Q 個のクエリが与えられるので、与えられた A 以下の最大の 400 number の値を求めよ。
ただし A 以下の 400 number は常に存在することが保証されている。

「各素因数でその数が割り切れる回数は偶数回」とはその数が平方数であることと同値です。また素因数が 2 種類しかないことはその数の平方根もまた 2 種類の素因数しか持たないことを意味しています。

2 種類の素因数しか持たないものを列挙するのであれば 030 – K Factors(★5) の方法がそのまま使えます。

A 以下で最大のものを探すのであれば二分探索法が有効です。二分探索の処理はライブラリ ac-library-csharp の StlFunction.BinarySearch メソッドを用いています。

参考: ac-library-csharpを使ってみる

E – Many LCMs

E – Many LCMs

問題の概要

長さ N の正整数列 A が与えられる。
k = 0, 1, 2, …, N – 1 について、A のなかから A[k] を除いた N – 1 個の要素の最小公倍数を 998244353 で割ったあまりを求めよ。
T 個のテストケースが与えられるので、それぞれについて答えを求めよ。

そのつど出力すべき最小公倍数を計算していては TLE 必至なので A 全体の最小公倍数 (LCM) を事前に計算しておきます。そのあと A[k] が取り除かれることで LCM がどう変化するのか考えます。

LCM で用いられている素因数の使用回数と A[k] で用いられている素因数の使用回数を比較します。もし両者が同じだと A[k] が取り除かれることで最小公倍数の値が小さくなります。その素因数の使用回数が A のなかで最大のものと二番目のものとの差だけその使用回数が少なくなるのです。

使用回数が少なくなる素因数とその回数がわかればあとは LCM をその素因数でその回数だけ割ればいいのですが、わり算の剰余に対して除算はできないので逆元を計算して掛け合わせることで対応します。

E – LCM Sequence

E – LCM Sequence

問題の概要

正整数 n について A[n] を 1, 2, …, n の最小公倍数として定義する。
正整数 L, R が与えられます。数列 (A[L], A[L+1], …, A[R]) の中には何種類の整数が含まれるか求めよ。

数列 A は広義単調増加数列です。A[n] に含まれる素因数を考えます。

A[2] -> {2}
A[3] -> {2, 3}
A[4] -> {2, 2, 3}
A[5] -> {2, 2, 3, 5}
A[6] -> {2, 2, 3, 5}
A[7] -> {2, 2, 3, 5, 7}
A[8] -> {2, 2, 2, 3, 5, 7}

n が素数であるとき素因数の種類が増えるので A[n] の値は増えます。また素数でなくても単一素数の正の整数乗になっている場合(素数冪という)はその素数が素因数の使用回数を 1 増やします。なので L + 1 以上、R 以下の素数冪の個数を数えれば n が L から R まで増えたときの個数の増加数がわかります。これに 1(最初の A[L] のぶん)を加えたものが解となります。

R が大きな値になっていますが、R – L がそれほど大きな値でなければ 097 – Primes in an Interval でも用いたエラストテネスの区間篩でなんとかなります。

素数冪であるかどうかは 10^7 までの素数をすべて求めてその整数乗を計算します。素数冪であっても R よりも大きなものはいらないのでそんなに処理に時間はかかりません。