AT274の技術だったりなかったり

あっとのTECH LOG

競プロのこととか技術のこととか。たまに日常を書きます。

ABC134 D - Preparing Boxes

問題原文

atcoder.jp

問題要旨

 N 個の箱が横一列に並んでおり、それぞれの箱には  0 か「tex: 1」 が書かれている。 それぞれの箱につい玉を1つ入れる or 入れないを適切に選ぶことで、  1 \leq i \leq N を満たす任意の整数  i について、
 i の倍数が書かれた箱に入っているボールの個数の和を2で割った余りが、箱  i に書かれた数字に一致するようにせよ。

  •  1 \leq N \leq 2 × 10^{5}

解法

すでに「玉を入れる / 入れない」の選択をした箱について、もう一度チェックすることは避けたい。 もう一度チェックしなければならないような状況 = すでにチェックした箱番号の倍数の箱のボールの数が変化するような状況、である。

 i に玉を入れることで影響が出るのは、  i の約数の箱番号である。
当然  i の約数は  i 以下なので、  i 以下の箱に影響が出る可能性がある と言える。

つまり、  i が大きい方から計算していけばいい。

計算量は一見 [tex: O(N2)] だが、調和級数に似た形をしているので、 実は  O(NlogN) となる。
 i が大きければ大きいほど、チェックする箱は少なくなるので、 O(N2) よりぐっと計算量が落ちそうなことが感覚的にわかる)

実装

N = int(input())
A = [0] + list(map(int, input().split()))
 
B = [0] * (N + 1)
for i in reversed(range(1, N + 1)):
    ball = 0
    base = i + 1
 
    for j in range(i, N + 1, i):
        ball += B[j]
 
    if ball % 2 != A[i]:
        B[i] = 1
 
print(sum(B))
print(*[i for i, b in enumerate(B) if b == 1], sep=' ')

range の第3引数を使えば楽に実装できる。あと、 1-indexedにすると楽。

感想

いい問題。