解説


この問題は「クエスト」「素因数」を頂点として「クエストを受注、クリアして素因数を貰う」を辺としたグラフにおける最小辺被覆問題に帰着することができます。 という制約により、このグラフには孤立点がないため次式が成立します。

このグラフは二部グラフになるため最大マッチングは最大流問題に帰着することができ(二部マッチング)、頂点数・辺数をそれぞれ とおくと、Dinic 法を用いることで計算量 で解くことができます。各クエストの素因数を求める前計算を加えると全体では となり、以上により最小辺被覆が求まります。

最小辺被覆を知らなかったとしても「二部マッチングを構築してから、余った頂点を一つずつ加えていけば最適になりそう」という考えに至れば解くことは可能です(これは最小辺被覆の構築手順そのものです)。

ちなみに、最小辺被覆は蟻本にも「最小辺カバー」として紹介されています。

計算量解析


(Dinic 法の計算量の詳細については下部の参考リンクをご確認ください)

頂点数と辺数をそれぞれ とおくと、一般に Dinic 法の計算量は となりますが、二部マッチングの場合は辺の容量がすべて であるため にまで改善され、 という評価をすることもできます。

次に、本問での頂点数 と辺数 の個数について述べます。

以下の素数は全部で 個ありますが、 の制約であるため、登場する素因数の種類数の最大は 程度となります(後述する整数などによって "素因数の種類数を稼ぐ" ことは可能ですが、そのような整数はほとんど作れないことが分かります)。よって、頂点数 の最大数は 程度と見積もれます。

一方、 の制約において が持つ素因数の最大数は、下記ケースを考えることで 個であると分かります。よって、辺数 の最大数は 程度と見積もれます(source と sink に張られる辺も含まれることに注意)。

以上により、最大流の計算量は のときが最悪ケースとなりますが、 程度であるため間に合います( の最悪ケースが両立するテストケースは作れないため、実際の計算量はもう少し小さくなります)。

参考


解答例


解答例では「素因数に番号を振る処理」に連想配列を用いていますが、制約が であることから、長さ の配列を代わりに用いて素因数の番号を管理する実装も可能です。

また、高速素因数分解を用いることで素因数分解パートを高速化することができます。最大流パートも同程度の計算量であるため全体では定数倍高速化となります。

解答例(C++)
解答例(Python)