考え方
Editorial - AtCoder Beginner Contest 272$N$個の整数に含まれない最小の非負整数は$0,1,...,N$のいずれか.
各$i$を考える.$m$回目の操作のあとで$A_{i} \in [0, N]$となる$m$の個数は,
\begin{aligned}
& 0 \leq A_{i} + m i \leq N \\
& \Leftrightarrow - \frac{A_{i}}{i} \leq m \leq \frac{N - A_{i}}{i}
\end{aligned}
により$O(N / i)$個.& 0 \leq A_{i} + m i \leq N \\
& \Leftrightarrow - \frac{A_{i}}{i} \leq m \leq \frac{N - A_{i}}{i}
\end{aligned}
したがって,すべての$i$について$A_{i} \in [0, N]$となる場合を調べると
\begin{aligned}
\sum_{i = 1}^{N} O(N / i)
=O(N\log N)
\end{aligned}
の計算量となる.\sum_{i = 1}^{N} O(N / i)
=O(N\log N)
\end{aligned}
よって,
- $1, 2,...,M$回目に現れる数をすべて調べて,回数ごとに保持しておき($O(N\log N)$)
- 各回数で保持した数を順に見ていって,現れないものを見つける($O(N\log N)$)
回答例
N, M = map(int, input().split()) A = list(map(int, input().split())) memo = [set() for _ in range(M)] for i in range(N): a = A[i] if a < 0: j = (- a // (i + 1)) - 1 a += (- a // (i + 1)) * (i + 1) else: j = 0 a += i + 1 while j < M: if a > N: break memo[j].add(a) j += 1 a += i + 1 for j in range(M): ans = 0 while ans in memo[j]: ans += 1 print(ans)
参考
アライグマ「図が間違ってるのだ。N=5だから5はメモしなくていいのだ」
— 競技プログラミングをするフレンズ (@kyopro_friends) October 8, 2022