ABC466 F - Many Mod Calculation

連続剰余

考え方

$1$ 以上 $X$ 以下の全ての数に対して処理を行ったときに、どういう値が何個あるのか持てばよい。
もちろん、愚直にやっては $O(X)$ 個の情報をもつことになって、計算量もメモリも足らない。

そこで、特殊な圧縮をしてデータを持つことにする。
つまり、「$0$ 以上 $k$ 未満の値が $1$ つずつある」みたいな形で持つ。
すると、このカタマリを A[i] で割った余りも、類似の形式複数個で表現できる。
具体的には、「$0$ 以上 $k$ 未満の値が $l$ 個ずつある」データを $a$ で割る場合は、以下。

あとはこれを、同じ範囲のものは可能な限りデータをまとめていく工夫をすればよい。
範囲が A[i] を超えるものの抽出は、priority_queue などを用いればよい。

与えられる問題は $0$ 以上ではなく $1$ 以上であるため、そこだけ困ったように見える。
が、「$0$ 以上 $1$ 未満の値が $-1$ 個ずつある」を入れておくことで解消できる。
しかも、これが番兵として機能してくれるため、コード的にも都合がいい。

計算量の見積もりは非常に難しいが、中途半端な長さのデータは最大でも $O(N)$ 個しか出てこない。
また、$1$ つのデータの幅は、剰余を $1$ 回とられるたびに半分未満になる。
これらのことから、全体で $O(N \log N \log X)$ であるため、間に合う。

入力例1での動作

$1$ つめのテストケースのみ。
入力を受け取る。

n: 3
x: 7
a: {5, 2, 3}

最初は、$1$ 以上 $7$ 以下が $1$ 個ずつある状態を、次の $2$ つの区間で表す。

[0,8): 1個
[0,1): -1個

まず $5$ で余りを取る。
$[0,8)$ は、$0$ から $4$ が $1$ 周分と、$0$ から $2$ がもう $1$ 周分現れる。

[0,8): 1個
  -> [0,5): 1個
  -> [0,3): 1個

$[0,1)$ はそのままなので、この時点の状態は次のようになる。

[0,5): 1個
[0,3): 1個
[0,1): -1個

次に $2$ で余りを取る。
$[0,5)$ からは $[0,2)$ が $2$ 個と $[0,1)$ が $1$ 個できる。
$[0,3)$ からは $[0,2)$ が $1$ 個と $[0,1)$ が $1$ 個できる。

既にあった $[0,1)$ の $-1$ 個も合わせると、同じ区間をまとめた状態は次のようになる。

[0,2): 3個
[0,1): 1個

最後に $3$ で余りを取る。
どちらの区間も上限が $3$ 以下なので、状態は変化しない。

[0,2): 3個
[0,1): 1個

どの区間にも $0$ が $1$ つずつ含まれる。
したがって、最終的に $0$ となる数の個数は $3+1=4$ であり、答えは $4$ となる。

注意点

$X$ や $A_i$ は、int 型からはみ出る。
long long 型を用いること。

別解

特になし。