G - Doubles Editorial by amentorimaru

定数倍高速化による解法

基本的には公式解説と同様になります。

それぞれのサイコロ \(i\) に対して \(1\) 以上 \(\max{A}\) 以下の \(j\) の目が何回出てくるかを連想配列ではなく二次元配列として \(C_{ij}\) 所持しておきます。

サイコロ \(i_1,i_2\) を振った時に同じ目が出る場合の数は \(\sum_{j=1}^{\max{A}} C_{i_1j}C_{i_2j}\) となり、この合計に対して \(K_iK_j\) を割ることによりそれぞれの組み合わせの答えを導くことができます。

これを全てのサイコロの組み合わせで計算すると \(O(N^2 \max{A})\) となり、おおよそ \(10^9\) の計算量となり時間制限超過が予測されます。

しかし十分に高速な処理の上では表記上 \(10^9\) 以上となっても制限時間内に十分間に合わせることは可能であり、全てのサイコロの組み合わせで \(O(N^2)\) に対して2倍の定数倍高速化ができていることに加え、ボトルネックになっている \(O(\max{A})\) 部分の計算は乗算と加算一回ずつの非常に軽い動作であるため、C++などの高速な言語を用いることで間に合わせることができるほか、上記の総和の計算式はPythonの場合numpyのdot関数での高速化が可能です。

これらを利用すると制限時間超過すると思われる計算量に対しても制限時間内に対して十分な速さで解答することができます。

Numpyのdotによる実装例 : https://atcoder.jp/contests/abc392/submissions/62584682

posted:
last update: