Dịch chuyển đa thức | Dịch chuyển giá trị điểm liên tục
Tịnh tiến đa thức
Tịnh tiến đa thức là một trường hợp đơn giản của phép hợp thành đa thức. Cho hệ số của \(f(x)=\sum _ {i=0}^nf_ix^i\) và một hằng số \(c\), hãy tìm hệ số của \(f(x+c)\), tức \(f(x)\mapsto f(x+c)\).
Phương pháp chia để trị
Đặt
khi đó
Hệ số của \((x+c)^{\left\lfloor n/2\right\rfloor}\) là các hệ số nhị thức, do đó
trong đó \(O(n\log n)\) là thời gian nhân đa thức.
Phương pháp công thức Taylor
Áp dụng công thức Taylor của \(f(x)\) tại \(c\):
Suy ra
Nhận thấy với \(t\geq 0\):
Đặt
thì
Phương pháp định lý nhị thức
Xét định lý nhị thức \(\displaystyle (a+b)^n=\sum _ {i=0}^n\binom{n}{i}a^ib^{n-i}\), ta có
Kết quả trùng với các phương pháp trên.
Tịnh tiến giá trị tại các điểm liên tiếp
Ví dụ LOJ 166 Nội suy Lagrange 2
Cho các giá trị liên tiếp \(f(0),f(1),\dots ,f(n)\) của đa thức \(f\) bậc không vượt quá \(n\). Tính \(f(c),f(c+1),\dots ,f(c+n)\) theo modulo \(998244353\), với \(1\leq n\leq 10^5,n < m\leq 10^8\).
Phương pháp công thức nội suy Lagrange
Xét công thức nội suy Lagrange:
Dù là dạng tích chập nhưng không đảm bảo \(x-i\neq 0\) ở mẫu, nên dưới đây chỉ xét \(c > n\). Các trường hợp khác (ví dụ hệ số theo modulo số nguyên tố cần tránh mẫu của \(B_0(x)\) bằng 0) có thể xử lý phân trường hợp. Đặt
khi đó với \(t\geq 0\):
Trong cài đặt có thể cắt bớt phần cần thiết của \(B_0(x)\) để lấy nhiều điểm hơn, và có thể dùng tích chập vòng.
Sửa bài toán một chút: giả sử ta có các giá trị \(f(d),f(d+k),\dots ,f(d+nk)\), thì có thể tính \(f(c+d),f(c+d+k),\dots ,f(c+d+nk)\) bằng cách coi đó là tịnh tiến các giá trị của \(g(x)=f(d+kx)\) từ \(g(0),g(1),\dots ,g(n)\) sang \(g(c/k),g(c/k+1),\dots ,g(c/k+n)\).
Công thức nội suy Lagrange cũng cho cách tính tuyến tính một điểm bằng cách duy trì các tích tiền tố/hậu tố.
Ứng dụng
Các số Stirling loại một không dấu trên cùng một hàng
Ví dụ P5408 Stirling loại một · hàng
Tính \(\displaystyle {n\brack 0},{n\brack 1},\dots ,{n\brack n}\) theo modulo số nguyên tố \(167772161\), với \(1\leq n< 262144\).
Xét
trong đó \(x^{\overline{n}}=x\cdot (x+1)\cdots (x+n-1)\) là lũy thừa giai thừa tăng. Đặt \(f_n(x)=x^{\overline{n}}\), ta có
Tịnh tiến đa thức cho phép tính \(f_n(x+n)\) trong \(O(n\log n)\), kích thước bài toán giảm một nửa, nên
Giai thừa theo modulo số nguyên tố
Ví dụ P5282【Mẫu】Thuật toán giai thừa nhanh
Tính \(n!\bmod p\), với \(p\) là số nguyên tố và \(1\leq n< p\leq 2^{31}-1\).
Đặt \(v=\lfloor\sqrt{n}\rfloor\) và \(g(x)=\prod _ {i=1}^v(x+i)\), khi đó
Trong đó \(\prod _ {i=v^2+1}^n i\) tính được trong \(O(\sqrt{n})\), ta muốn tính nhanh phần đầu.
Đa điểm giá trị đa thức
Hệ số \(g(x)\) có thể tính bằng thuật toán tịnh tiến đa thức trong \(O(n\log n)\), nhưng tính \(g(0),g(v),g(2v),\dots ,g(v^2-v)\) bằng đa điểm giá trị cần \(O(\sqrt{n}\log ^2n)\).
Tịnh tiến giá trị tại các điểm liên tiếp
Đặt \(g_d(x)=\prod _ {i=1}^d(x+i)\), ta có thể dùng \(d+1\) điểm \(g_d(0),g_d(v),\dots ,g_d(dv)\) để xác định duy nhất đa thức bậc \(d\). Mặt khác
nên chỉ cần \(2d+1\) điểm là xác định được \(g _ {2d}(x)\). Khi đó dùng tịnh tiến điểm liên tiếp để tính \(g_d((d+1)v),g_d((d+2)v),\dots ,g_d(2dv)\) (tức tịnh tiến điểm của \(h(x)=g_d(vx)\) từ \(h(0),h(1),\dots ,h(d)\) sang \(h(d+1),h(d+2),\dots ,h(2d)\)) và \(g_d(d),g_d(v+d),\dots ,g_d(2dv+d)\) (tức tịnh tiến điểm của \(h(x)=g_d(vx)\) từ \(h(0),h(1),\dots ,h(d)\) sang \(h(d/v),h(d/v+1),h(d/v+2),\dots ,h(d/v+2d)\)). Nhân từng cặp điểm tương ứng sẽ được \(g _ {2d}(0),g _ {2d}(v),\dots ,g _ {2d}(2dv)\).
Từ \(g_d(0),g_d(v),\dots ,g_d(dv)\) tính \(g _ {d+1}(0),g _ {d+1}(v),\dots ,g _ {d+1}(dv),g _ {d+1}((d+1)v)\), xét
Điểm bổ sung có thể tính tuyến tính. Khởi tạo \(g_1(0)=1,g_1(v)=v+1\), rồi dùng tịnh tiến điểm liên tiếp để nhân đôi và duy trì các điểm, ta có
Ta chỉ cần khoảng \(\sqrt{n}\) điểm, nên tổng thời gian \(O(\sqrt{n}\log n)\).
Tổng tiền tố hệ số nhị thức theo modulo số nguyên tố
Ví dụ LOJ 6386 Tổng tiền tố tổ hợp
Tính \(\displaystyle \sum _ {i=0}^m\binom{n}{i}\bmod 998244353\), với \(0\leq m\leq n\leq 9\times 10^8\).
Xét truy hồi \(n!=n\cdot (n-1)!\) dưới dạng ma trận:
Tương tự, truy hồi của tổng tiền tố hệ số nhị thức:
Chú ý thứ tự nhân ma trận, ta có
Đặt \(v=\lfloor\sqrt{m}\rfloor\), xét ma trận
Ta duy trì các điểm \(M _ d(0),M _ d(v),\dots ,M_d(dv)\), tức các điểm của \(f_d,h_d,g_d\), và
Phần tử góc phải dưới chính là thứ cần duy trì trong bài giai thừa, nên
Có thể tính trong \(O(\sqrt m\log m)\).
Số điều hòa theo modulo số nguyên tố
Ví dụ P5702 Tổng cấp số điều hòa
Tính \(\sum _ {i=1}^ni^{-1}\bmod p\), với \(p\) là số nguyên tố và \(1\leq n< p< 2^{30}\).
Đặt \(H_n=\sum _ {k=1}^nk^{-1}\), truy hồi một bước:
Suy ra
Ở đây \(\displaystyle {n+1\brack 1}\) và \(\displaystyle {n+1\brack 2}\) là số Stirling loại một không dấu. Cách duy trì ma trận điểm giống như trên.
Truy hồi đa thức
Với trường hợp tổng quát hơn, tương tự bài giai thừa nhanh ở trên, ta cần một thuật toán như thế nào?
Ví dụ P6115【Mẫu】Truy hồi đa thức
Dãy \(a\) thỏa \(\forall n\ge m,\sum_{k=0}^ma_{n-k}P_k(n)=0\), trong đó \(P_k\) là đa thức bậc không vượt quá \(d\).
Cho hệ số của các \(P_k\) và \(a_0,a_1,\dots,a_{m-1}\), tính \(a_n\) theo modulo \(998244353\). \(n\le6\times10^8\),\(1\le m,d\le7\),giới hạn thời gian \(7s\).
Để mô tả hệ thống hóa cách dựng ma trận trong các ví dụ trên, ta dùng khái niệm ma trận \(\lambda\).
Trong thuật toán giai thừa nhanh, ta không duy trì \(n!\) trực tiếp mà duy trì \(\prod_{i=0}^{T-1}(aT+i)\), tức quan hệ nhân giữa hai điểm.
Với truy hồi đa thức bậc \(m>1\), ta không thể chỉ duy trì quan hệ nhân giữa hai số nữa; thay vào đó cần duy trì phép biến đổi tuyến tính giữa hai vector \(m\) chiều, tức một ma trận \(m\times m\), mỗi phần tử là một điểm của một đa thức.
Dễ thấy với truy hồi đa thức tổng quát để tính hệ số xa, ta có thể dựng:
Đặt
Bỏ qua hệ số \(-\frac1{P_0(n)}\), ta cần duy trì dạng \(\prod_{i=0}^{T-1}B(aT+m+i)\), nhân từ phải sang trái.
Dễ thấy \(B_T(\lambda)=\prod_{i=0}^{T-1}B(\lambda+i)\) là ma trận \(\lambda\) có bậc không quá \(dT\), chỉ cần \(dT+1\) giá trị để duy trì.
Ta duy trì các giá trị điểm của \(B_T(m)\), \(B_T(m+T)\), \(B_T(m+2T)\), \(\dots\),\(B_T(m+(dT-1)T)\), \(B_T(m+dT^2)\), rồi dùng cách tương tự giai thừa nhanh để tịnh tiến điểm và nhân đôi.
Cụ thể, để tăng \(t=\log_2T\) lên 1:
- Trong \(O(m^2dT\log(dT))\) tính \(B_T(p+dT^2)\), \(B_T(p+(dT+1)T)\), \(B_T(p+(dT+2)T)\), \(\cdots\),\(B_T(p+(2dT-1)T)\), \(B_T(p+(2dT)dT)\).
- Trong \(O(m^2dT\log(dT))\) tính \(B_T(p+2dT^2)\), \(B_T(p+(2dT+1)T)\), \(B_T(p+(2dT+2)T)\), \(\cdots\),\(B_T(p+(3dT-1)T)\), \(B_T(p+(3dT)dT)\).
- Trong \(O(m^2dT\log(dT))\) tính \(B_T(p+3dT^2)\), \(B_T(p+(3dT+1)T)\), \(B_T(p+(3dT+2)T)\), \(\cdots\),\(B_T(p+(4dT-1)T)\), \(B_T(p+(4dT)dT)\).
- Tính \(B_{2T}(v)=B_{T}(v+T)B_{T}(v)\).
Mỗi vòng tốn \(O(m^2dT\log(dT))\) để tịnh tiến; đồng thời chỉ cần \(\Theta(dT)\) phép nhân ma trận, nên coi như \(O(m^3dT)\).
Cuối cùng chỉ cần \(T\ge\sqrt{n/d}\).
Hệ số \(-\frac1{P_0(n)}\) phía trước xử lý tương tự.
Độ phức tạp tiền xử lý là \(\Theta(\sqrt{nd}(m^3+m^2\log(nd)))\).
Khi truy vấn, ta cần \(\Theta(n/T)\) phép nhân vector–ma trận, và \(O(T)\) bước chuyển thẳng.
Phần này không phải nút thắt chính.
Vì vậy tổng độ phức tạp là \(\Theta(\sqrt{nd}(m^3+m^2\log(nd)))\).
Trong cài đặt có thể dùng tích chập vòng để giảm hằng số của NTT.
Trong ứng dụng thực tế, thường là trích hệ số xa của một hàm sinh có đạo hàm hữu hạn; khi đó \(m,d\) là hằng số, đạt \(\Theta(\sqrt n\log n)\).
Tài liệu tham khảo
- Alin Bostan, Pierrick Gaudry, and Eric Schost. Linear recurrences with polynomial coefficients and application to integer factorization and Cartier–Manin operator.
- Blog của Min_25
- Blog của ZZQ - giai thừa modulo số nguyên tố lớn
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