Powerful Number (gọi tắt PN) sieve tương tự Du Jiao sieve, hoặc có thể xem là một mở rộng của Du Jiao sieve, dùng để tính prefix sum của một số hàm tích tính.
Yêu cầu:
Tồn tại hàm \(g\) thỏa:
\(g\) là hàm tích tính.
\(g\) dễ tính prefix sum.
Với số nguyên tố \(p\), \(g(p) = f(p)\).
Giả sử cần tính prefix sum của hàm tích tính \(f\): \(F(n) = \sum_{i=1}^{n} f(i)\).
Powerful Number
Định nghĩa: Với số nguyên dương \(n\), phân tích \(n = \prod_{i=1}^{m} p_{i}^{e_{i}}\). \(n\) là PN khi và chỉ khi \(\forall 1 \le i \le m, e_{i} > 1\).
Tính chất 1: Mọi PN đều có thể viết dưới dạng \(a^{2}b^{3}\).
Chứng minh: Nếu \(e_i\) chẵn thì gộp \(p_{i}^{e_{i}}\) vào \(a^{2}\); nếu \(e_i\) lẻ thì gộp \(p_{i}^{3}\) vào \(b^{3}\), sau đó gộp \(p_{i}^{e_{i}-3}\) vào \(a^{2}\).
Tính chất 2: Số PN không vượt quá \(n\) nhiều nhất là \(O(\sqrt{n})\).
Chứng minh: Xét liệt kê \(a\), rồi đếm số \(b\) thỏa điều kiện, số PN xấp xỉ
Vậy làm sao tìm tất cả PN \(\le n\)? Dùng sàng tuyến tính tìm các số nguyên tố \(\le \sqrt{n}\), rồi DFS liệt kê các số mũ của các nguyên tố. Do số PN \(\le n\) nhiều nhất \(O(\sqrt{n})\), nên số lần tìm kiếm tối đa \(O(\sqrt{n})\).
PN sieve
Đầu tiên, xây dựng hàm tích tính \(g\) dễ tính prefix sum và thỏa \(g(p)=f(p)\) với mọi nguyên tố \(p\). Đặt \(G(n) = \sum_{i=1}^{n} g(i)\).
Sau đó, định nghĩa \(h = f / g\), trong đó \(/\) là phép chia theo chập Dirichlet. Theo tính chất chập Dirichlet, \(h\) cũng là hàm tích tính, nên \(h(1)=1\). Ta có \(f = g * h\) (với \(*\) là chập Dirichlet).
Với nguyên tố \(p\), \(f(p) = g(1)h(p) + g(p)h(1) = h(p) + g(p) \implies h(p) = 0\). Từ \(h(p)=0\) và tính tích tính của \(h\) suy ra với số không phải PN thì \(h(n)=0\), tức \(h\) chỉ khác \(0\) tại PN.
Tìm tất cả PN trong \(O(\sqrt{n})\), tính các giá trị hữu hiệu của \(h\). Để tính \(h\) chỉ cần tính \(h(p^c)\), sau đó dùng tính tích tính để suy ra \(h\) ở các PN khác. Với mỗi giá trị hữu hiệu \(d\), tính \(h(d)G\left(\left\lfloor \dfrac{n}{d} \right\rfloor\right)\) và cộng lại để thu được \(F(n)\).
Xét cách tính \(h(p^c)\), có hai cách: suy ra công thức chỉ phụ thuộc \(p,c\); hoặc dùng \(f = g * h\) có \(f(p^c) = \sum_{i=0}^c g(p^i)h(p^{c-i})\), suy ra \(h(p^c) = f(p^c) - \sum_{i=1}^{c}g(p^i)h(p^{c-i})\), rồi liệt kê \(p,c\) để tính toàn bộ \(h(p^c)\).
Quy trình
Xây dựng \(g\)
Xây dựng cách tính nhanh \(G\)
Tính \(h(p^c)\)
Duyệt PN, trong quá trình cộng dồn đáp án
Lấy kết quả
Bước 3 có thể dùng công thức trực tiếp, hoặc tiền xử lý bằng liệt kê, hoặc tính tạm khi cần.
Phân tích
Lấy cách 2 để phân tích. Chia thành phần tính \(h(p^c)\) và phần tìm kiếm.
Với phần 1, số nguyên tố \(\le \sqrt{n}\) là \(O\left(\dfrac{\sqrt{n}}{\log n}\right)\). Mỗi nguyên tố có số mũ tối đa \(\log n\). Tính \(h(p^c)\) cần lặp \((c-1)\) lần, nên độ phức tạp \(O\left(\dfrac{\sqrt{n}}{\log n} \cdot \log n \cdot \log n\right) = O(\sqrt{n}\log{n})\). Đây là cận trên lỏng; tùy bài có thể tối ưu thêm.
Phần tìm kiếm: do số PN \(\le n\) là \(O(\sqrt{n})\), nên tối đa \(O(\sqrt{n})\) lượt. Với mỗi PN, tùy cách tính \(G\) mà độ phức tạp khác nhau. Ví dụ nếu \(G\left(\left\lfloor \dfrac{n}{d}\right\rfloor\right)\) là \(O(1)\) thì phần này là \(O(\sqrt{n})\).
Đặc biệt, nếu dùng Du Jiao sieve để tính \(G\left(\left\lfloor \dfrac{n}{d}\right\rfloor\right)\) thì độ phức tạp phần 2 là độ phức tạp Du Jiao sieve, tức \(O(n^{\frac{2}{3}})\). Vì nếu đã tính \(G(n)\) một lần và dùng sàng tuyến tính cộng với cấu trúc truy cập nhanh (như std::map/std::unordered_map) để lưu các giá trị lớn, thì các giá trị \(G\left(\left\lfloor \dfrac{n}{d}\right\rfloor\right)\) đều đã có trong sàng hoặc trong map.
Về bộ nhớ, nút thắt là lưu \(h(p^c)\). Nếu dùng mảng 2 chiều \(a\), \(a_{i,j}\) là \(h(p_i^j)\), thì bộ nhớ là \(O\left(\dfrac{\sqrt{n}}{\log n} \cdot \log n\right) = O(\sqrt{n})\).
Dùng Du Jiao sieve để tính \(G(n)\), theo \((\operatorname{id}\cdot \varphi) * \operatorname{id} = \operatorname{id}_2\) suy ra \(G(n)= \sum_{i=1}^{n} i^2 - \sum_{d=2}^{n} d \cdot G\left(\left\lfloor \dfrac{n}{d} \right\rfloor\right)\).
Sau đó \(h(p^k)\) có thể tính bằng liệt kê, phần này không lặp lại.
Ngoài ra có thể trực tiếp suy ra công thức \(h(p^k)\) chỉ phụ thuộc \(p,k\):
Last updated on this page:, Update history Found an error? Want to help improve? Edit this page on GitHub! Contributors to this page:OI-wiki All content on this page is provided under the terms of the CC BY-SA 4.0 and SATA license, additional terms may apply