Hướng dẫn giải của Tổng n trên dãy


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.

Lời giải này đang bị ẩn cho đến khi bạn chọn mở ra.

Chúng tôi khuyên bạn nên tự thử giải bài trước. Việc mở lời giải có thể làm lộ mất ý tưởng chính trước khi bạn có cơ hội tự giải.

Bạn phải đăng nhập để mở lời giải này.

Đăng nhập

Tác giả: Hiếu Nguyễn, kienylvp, hyhuy, nguyentienloi

Hiểu bài toán

Cho một số nguyên dương n. nhiệm vụ là tính tổng S = [n/1] + [n/2] + ... + [n/n], trong đó [x] là phần nguyên của x (tức là floor(x)). Với n lên tới 10^9, cách tiếp cận trực tiếp tính từng số hạng sẽ quá chậm.

Các cách tiếp cận

Cách Brute Force (Lặp thông thường)
long long s = 0;
for (long long i = 1; i <= n; i++) {
    s += n / i;
}
  • Time Complexity: O(n)
  • Space Complexity: O(1)

Duyệt tuần tự từ i = 1 đến n, tính giá trị n / i và cộng vào tổng. Vì n có thể lên tới 10^9, độ phức tạp O(n) sẽ dẫn đến TLE (Time Limit Exceeded).

Cách Phân loại giá trị (Math)
#include <bits/stdc++.h>
using namespace std;

int main() {
    long long n, s = 0;
    cin >> n;
    for (long long i = 1, j; i <= n; i = j + 1) {
        long long q = n / i;
        j = n / q;
        s += (j - i + 1) * q;
    }
    cout << s;
}
  • Time Complexity: O(sqrt(n))
  • Space Complexity: O(1)

Tính chất: Với n cố định, giá trị của n / i chỉ thay đổi O(sqrt(n)) lần. Cụ thể, nếu k = n / i thì i nằm trong khoảng [n/(k+1)+1, n/k]. Ta có thể nhóm các i lại thành các đoạn liên tục mà giá trị n/i không đổi. Vòng lặp chạy từ i=1, tính q = n/i, tìm j = n/q là chỉ số cuối cùng của đoạn. Sau đó cộng dồn q(j-i+1) và nhảy i về j+1. Số lần lặp chỉ khoảng 2sqrt(n).

Phân tích độ phức tạp

Cách tiếp cận Time Space Tên
1 O(n) O(1) Brute Force (Lặp thông thường)
2 O(sqrt(n)) O(1) Phân loại giá trị (Math)

Bài học kinh nghiệm

  • Giá trị của n/i chỉ thay đổi O(sqrt(n)) lần khi i chạy từ 1 đến n.
  • Đoạn [i, j] mà n/k không đổi có thể xác định nhanh chóng bằng j = n / (n/i).

Lỗi thường gặp

  • Sử dụng biến kiểu int导致 overflow khi n = 10^9 (n*n có thể xảy ra ở cách khác, nhưng ở đây cần long long cho biến tích累)
  • Quên cập nhật đúng bước nhảy i = j + 1 có thể gây ra vòng lặp vô hạn hoặc sai kết quả.

Bình luận

Please read the guidelines before commenting.


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