Editorial for Kaninho tập đếm


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.

Submitting an official solution before solving the problem yourself is a bannable offence.

Hint 1: Chỉ cần quan tâm các số không có ước chính phương

Hint 2: \(\sqrt{500} = 22.3\)

Hint 3: Mỗi số từ \(1\) đến \(500\) chỉ chứa tối đa một ước nguyên tố lớn hơn \(22\).

Hint 4:\(8\) số nguyên tố nhỏ hơn \(22\).

Hint 5: Gọi \(p(n)\) là ước nguyên tố lớn hơn 22 của \(n\). Nếu hai số \(m, n\)\(p(m) = p(n)\) thì ta chỉ có thể chọn tối đa một số.


Lời giải:

Đầu tiên, chia các số \(1, 2, ..., n\) vào các nhóm, số \(i\) thuộc nhóm \(p(i)\). Các số không có ước nguyên tố \(> 22\) thì xem mỗi số như một nhóm riêng.

Vì chỉ cần quan tâm các ước nguyên tố < 22, ta sẽ lưu trạng thái là 8 bit 0/1 cho 8 số nguyên tố < 22. Bit thứ \(i\) = 1 nếu số nguyên tố thứ \(i\) đã được chọn. \(dp[k][bit]\) cho ta biết số tập con có size = \(k\) và thỏa mãn điều kiện của \(bit\).

Với mỗi nhóm, chúng ta chọn ra tối đa một số. Vì vậy, chúng ta có thể for theo từng nhóm này. Giả sử trước một nhóm, chúng ta có mảng \(dp\_old[0..k][0..255]\). Chúng ta sẽ cập nhật như sau:

// không chọn số nào
for i = 0 to k:
  for bit = 0 to 255:
    dp[i][bit] = dp_old[i][bit]

// chọn 1 số trong nhóm
for i trong nhóm:
  tạo bitI là bit đại diện cho số i, bit thứ j = 1 nếu i chia hết số nguyên tố thứ j
  for bit = 0 to 255:
    if (bit | bitI) == 0:  // hai bit không giao nhau
      for j = 1 to k:
        dp[j][bit & bitI] += dp_old[j - 1][bitI]

Đáp số là tổng \(dp[0] + ... + dp[255]\).

Độ phức tạp: \(O(255 * nk)\)



Comments

There are no comments at the moment.