Chọn Đội tuyển HSGQG Quảng Trị 2024 - GCDS

Xem dạng PDF

Gửi bài giải

Điểm: 0,01 (OI)
Giới hạn thời gian: 2.5s
Giới hạn bộ nhớ: 512M
Input: GCDS.INP
Output: GCDS.OUT

Tác giả:
Dạng bài
Ngôn ngữ cho phép
C, C++, Go, Java, Kotlin, Pascal, PyPy, Python, Rust, Scratch

Cho dãy số nguyên dương ~a_1, a_2, \ldots, a_N~ có ~N~ phần tử. Việt Anh định nghĩa hàm ~f(i, j)~ là tổng của tất cả giá trị ~\frac{a_i \times a_j}{d^2}~ với ~d~ là một ước chung của ~a_i~ và ~a_j~. Ước chung của hai số nguyên dương ~x, y~ là số tự nhiên ~d~ mà ~x, y~ đều chia hết cho ~d~.

Ví dụ dãy ~A = \{2, 1, 4\}~ thì ~f(1, 3) = (2 \times 4)/1^2 + (2 \times 4)/2^2 = 10~ với ~\{1, 2\}~ là các ước chung của 2 và 4, ~f(1, 2) = (2 \times 1)/1^2 = 2~ và ~f(2, 3) = (1 \times 4)/1^2 = 4~.

Tổng GCDS của dãy số chính là tổng tất cả các ~f(i, j)~ định nghĩa ở trên sao cho ~1 \leq i < j \leq N~. Dãy ~A = \{2, 1, 4\}~ có tổng GCDS là ~f(1, 2) + f(1, 3) + f(2, 3) = 16~.

Việt Anh biết các bạn trường THPT Chuyên Lê Quý Đôn học lập trình rất tốt nên đưa ra bài toán như sau: Cho dãy số nguyên dương ~a_1, a_2, \ldots, a_N~ có ~N~ phần tử cần tính tổng GCDS của dãy số. Ngoài ra, Việt Anh còn thực hiện thêm ~Q~ truy vấn, với mỗi truy vấn cho hai số ~(x, y)~ gán phần tử ~a_x = y~. Hãy tính tổng GCDS của dãy số mới.

Yêu cầu: Cho dãy số nguyên dương ~a_1, a_2, \ldots, a_N~ có ~N~ phần tử, thực hiện:

  • Tính tổng GCDS của dãy số ban đầu;

  • Trả lời ~Q~ truy vấn, với mỗi truy vấn ~(x, y)~ hãy tính tổng GCDS của dãy số sau khi cập nhật ~a_x = y~.

Input

Dữ liệu vào từ tệp văn bản GCDS.INP có cấu trúc sau:

  • Dòng đầu tiên chứa hai số nguyên dương ~N~ và ~Q~ (~1 \leq N, Q \leq 5 \times 10^5~);

  • Dòng thứ 2 ghi dãy ~a_1, a_2, \ldots, a_N~ (~1 \leq a_i \leq 5 \times 10^5~);

  • ~Q~ dòng tiếp theo, mỗi dòng ghi hai số ~x~ và ~y~ biểu thị truy vấn gán ~a_x = y~ (~1 \leq x \leq N~, ~1 \leq y \leq 5 \times 10^5~).

Output

Kết quả ghi ra tệp văn bản GCDS.OUT gồm:

  • Dòng đầu tiên ghi phần dư của tổng GCDS của dãy số ban đầu khi chia ~10^9 + 7~;

  • ~Q~ dòng tiếp theo, mỗi dòng ghi một số là phần dư của tổng GCDS của dãy khi chia ~10^9 + 7~ tương ứng với thứ tự truy vấn trong tệp dữ liệu vào.

Scoring

Subtask Điểm Giới hạn
1 ~20\%~ ~N, Q, a_x, y \le 100~
2 ~30\%~ ~N, Q \le 100~
3 ~10\%~ ~a_x, y \le 12~
4 ~20\%~ ~a_x~ và ~y~ là số nguyên tố
5 ~20\%~ Không có ràng buộc nào thêm.

Sample Input 1

2 2
2 4
1 4
1 3

Sample Output 1

10
21
12

Sample Input 2

4 3
462955 253652 126897 278176
2 5432
1 2314
3 2

Sample Output 2

57273948
41211035
109845881
827916911

Bình luận

Hãy đọc nội quy trước khi bình luận.



  • 15
    YougiTuber  đã bình luận lúc 21, Tháng 8, 2025, 17:35

    Spoil ⚠️

    Xét hai số nguyên ~x~, ~y~. Gọi ~g~ là một trong các ước chung của ~x~ và ~y~.

    Gọi ~x'~ và ~y'~ gọi là các "ước riêng" của ~x~ và ~y~ theo ước chung ~g~.

    (~x' \cdot g = x~, và ~y' \cdot g = y~).

    Như vậy khi có bộ ~x, y~, ta sẽ nhận thêm ~x' \cdot y'~ vào kết quả. Đối với mỗi ~g~ là một ước của ~gcd(x, y)~, ta sẽ cộng thêm ~x' \cdot y'~ tương ứng với một ước đó.

    Nếu thêm một số ~x~ vào, và với một ước ~g~, ta cần tìm tất cả các số có ước ~g~ đó, và tính ~x' \cdot y'~. Vì mọi số có ước ~g~ đều đóng góp vào kết quả này, vì vậy, gọi sum[g] là tổng "ước riêng" của mọi số có một ước là ~g~, đối với ~y~ có ước là ~g~, ta cộng thêm ~y' = y / g~ vào sum[g], và sum[g] sẽ được nhân thêm ~x' = x / g~ rồi cộng vào kết quả.

    Ví dụ:

    Ta có tập số ~1, 2, 3, 3, 12~

    Xét số ~x = 6~ sẽ được thêm vào tập, có các ước là $1, 2, 3, 6$

    Với ~g = 1~, x' = 6, các số có ước là ~1~ là ~1, 2, 3, 3, 12~, y' = 1, 2, 3, 3, 12, kết quả được cộng thêm 6 * (1 + 2 + 3 + 3 +12)

    Với ~g = 2~, x' = 3, các số có ước là ~2~ là ~2, 12~, y' = 1, 6, kết quả được cộng thêm 3 * (1 + 6)

    Với ~g = 3~, x' = 2, các số có ước là ~3~ là ~3, 3, 12~, y' = 1, 1, 4, kết quả được cộng thêm 2 * (1 + 1 + 4)

    Với ~g = 6~, x' = 1, các số có ước là ~6~ là ~12~, y' = 2, kết quả được cộng thêm 1 * 2.

    Các tổng trên lần lượt được lưu trong ~sum[1]~, ~sum[2]~, ~sum[3]~, ~sum[6]~, đồng thời các ~x'~ của ~6~ cũng được cộng thêm vào ~sum[g]~ tương ứng.

    Vì vậy, khi thêm một số vào tập, ta có thể duyệt qua các ước ~g~ của số đó, và cộng thêm kết quả tương ứng theo ~sum[g]~.

    Việc gán một phần tử bằng giá trị khác, chính là xóa phần tử cũ khỏi tập, và thêm phần tử mới vào tập. Ta sẽ code một hàm xóa với logic gần tương tự

    Các ước của một số có thể lưu vào một danh sách với độ phức tạp của sàng đếm ước.

    Độ phức tạp

    O(~n \cdot \text{log}_n~ + ~q \cdot d * 2~), với ~d~ là số ước của một số trong mảng (Tối đa khoảng ~200~)