trang chủ / đề bài / pfprodmod / lời giải

Tích đoạn modular

Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Tác giả: huunguyenhuunguyen

Hướng tiếp cận

Đặt p0=1 và pi=pi−1·aimodMOD là tích tiền tố modular. Khi đó

al·al+1·…·ar≡prpl−1(modMOD).

Vì MOD là số nguyên tố và ai≠0, mọi pi≠0 trong ℤ/MODℤ, do đó nghịch đảo pl−1−1 tồn tại.

Nhận xét quan trọng

Phép chia thông thường không phù hợp: với tích tiền tố đã lấy modulo, pr/pl−1 trong ℤ không cho ra kết quả đúng. Ta phải dùng nghịch đảo modular.

Theo định lý nhỏ Fermat: xMOD−2≡x−1(modMOD) với mọi x không chia hết cho MOD.

Thuật toán

Có hai cách triển khai:

Cách 1 — Tính nghịch đảo trên từng truy vấn. Với mỗi truy vấn (l,r), tính inv=pl−1MOD−2modMOD bằng luỹ thừa nhanh, sau đó đáp án là pr·invmodMOD. Mỗi truy vấn mất O(logMOD).

Cách 2 — Tính trước nghịch đảo (khuyên dùng).

  1. Tính tích tiền tố p0,p1,…,pn.
  2. Tính nghịch đảo của tích tiền tố cuối: invp[n]=pnMOD−2modMOD.
  3. Suy ngược: invp[i]=invp[i+1]·ai+1modMOD.

Khi đó mỗi truy vấn được trả lời trong O(1):

ans=pr·invp[l−1]modMOD.

Độ phức tạp

  • Cách 1: O((n+q)logMOD).
  • Cách 2: O(n+q+logMOD) — chỉ một phép luỹ thừa nhanh duy nhất.

Bộ nhớ: O(n).

Lưu ý cài đặt. Trong C++, dùng long long cho phép nhân vì ai,pi có thể đạt 109, và tích hai số như vậy cỡ 1018 vẫn nằm trong long long nhưng tràn nếu dùng int.


Bình luận

Không có bình luận tại thời điểm này.

gnatmake 12.2.0 a68g 3.1.2 nasm 2.16.1 as_x64 2.47 awk 1.3.4 gcc 16.2.0 dotnet 10.0.402 g++ 16.2.0 g++-themis 16.2.0 g++17 16.2.0 g++20 16.2.0 g++23 16.2.0 clang++ 22.1.8 dmd 2.113.0 dart 3.13.6 gforth 0.7.3 gfortran 15.3.0 go 1.27.3 groovyc 5.1.3 javac 26.0.2.1 node 26.12.1 julia 1.13.2 kotlinc 2.4.21 lean 4.35.0 sbcl 2.2.9 lua 5.5.1 nim 2.2.12 fpc 3.2.2 fpc-themis 3.2.2 perl 5.42.3 php 8.5.12 pike 8.0 swipl 9.0.4 pypy3 7.3.23 python3 3.15.1 racket 8.7 ruby 4.0.8 rustc 1.99.1 csc 5.3.0 ctoj-scratch 0.0.1 sed 4.9 swiftc 6.4.1 tclsh 8.6 bun 1.4.4 deno 2.9.8 v 0.5.2 zig 0.17.0