Hướng dẫn giải của Tổng các số lẻ
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ậpTác giả: , , ,
Hiểu bài toán
Bài toán yêu cầu tính tổng tất cả các số lẻ nằm trong khoảng từ số nguyên l đến r (bao gồm cả l và r). Dữ liệu đầu vào có thể rất lớn (lên đến ~10^9), do đó cần một giải pháp hiệu quả về thời gian thực thi và bộ nhớ.
Các cách tiếp cận
Cách Vòng lặp (Brute Force)
#include <bits/stdc++.h>
using namespace std;
int main() {
long long l, r;
cin >> l >> r;
// Tìm số lẻ đầu tiên >= l
if (l % 2 == 0) l++;
long long sum = 0;
for (long long x = l; x <= r; x += 2) {
sum += x;
}
cout << sum;
return 0;
}
- Time Complexity: O(n)
- Space Complexity: O(1)
Phương pháp này sử dụng một vòng lặp để duyệt qua các số lẻ từ số lẻ đầu tiên >= l đến r, mỗi bước nhảy 2 đơn vị.
- Kiểm tra nếu
llà số chẵn, tăngllên 1 để biến thành số lẻ. - Khởi tạo biến
sum = 0. - Lặp từ
lđếnrvới bước nhảy 2 (x += 2), cộng dồn vàosum. - In ra kết quả.
Cách này rất trực quan và dễ hiểu. Tuy nhiên, với r lên tới 10^9, số lượng số lẻ trong đoạn có thể lên tới 5*10^8, vòng lặp sẽ chạy quá lâu và gây ra lỗi 'Time Limit Exceeded'. Do đó, giải pháp này chỉ khả thi với dữ liệu nhỏ.
Cách Công thức tổng quát (Optimal)
#include <bits/stdc++.h>
using namespace std;
int main() {
long long l, r;
cin >> l >> r;
long long first = (l % 2 == 1) ? l : l + 1;
long long last = (r % 2 == 1) ? r : r - 1;
if (first > last) {
cout << 0;
return 0;
}
long long n = (last - first) / 2 + 1;
long long sum = n * (first + last) / 2;
cout << sum;
return 0;
}
- Time Complexity: O(1)
- Space Complexity: O(1)
Phương pháp này sử dụng công thức toán học để tính tổng không cần vòng lặp, do đó có độ phức tạp hằng số thời gian O(1).
- Tìm số lẻ đầu tiên (
first) trong đoạn: Nếullà số lẻ thìfirst = l, ngược lạifirst = l + 1. - Tìm số lẻ cuối cùng (
last) trong đoạn: Nếurlà số lẻ thìlast = r, ngược lạilast = r - 1. - Kiểm tra điều kiện: Nếu
first > last(ví dụ đoạn [2, 3] nhưng 2 là chẵn -> first=3, last=2 -> không có số lẻ), in ra 0. - Nếu có số lẻ, tính số lượng các số lẻ:
n = (last - first) / 2 + 1. - Tính tổng các số lẻ bằng công thức tổng của cấp số cộng:
sum = n * (first + last) / 2.
Đây là giải pháp tối ưu nhất.
Cách Tối ưu vòng lặp (Cải tiến)
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long l,r,ssh;
cin>>l>>r;
if(l%2==0)
{
l++;
}
if(r%2==0)
{
r--;
}
ssh=(r-l)/2+1;
cout<<(l+r)*ssh/2;
}
- Time Complexity: O(1)
- Space Complexity: O(1)
Đây là biến thể của phương pháp công thức tổng quát, có cấu trúc mã nguồn gọn hơn.
- Chuẩn hóa
l: Nếullà chẵn,l++để lấy số lẻ đầu tiên. - Chuẩn hóa
r: Nếurlà chẵn,r--để lấy số lẻ cuối cùng. - Tính
ssh(số lượng số lẻ):(r - l) / 2 + 1. Lưu ý ở đây biếnsshchính làntrong phương pháp trước. - Tính tổng:
(l + r) * ssh / 2.
Giải pháp này cũng mang lại hiệu quả O(1) và là cách tiếp cận thường thấy trong các bài toán tính tổng theo quy luật.
Phân tích độ phức tạp
| Cách tiếp cận | Time | Space | Tên |
|---|---|---|---|
| 1 | O(n) | O(1) | Vòng lặp (Brute Force) |
| 2 | O(1) | O(1) | Công thức tổng quát (Optimal) |
| 3 | O(1) | O(1) | Tối ưu vòng lặp (Cải tiến) |
Bài học kinh nghiệm
- Bài toán có thể biến về bài toán tính tổng của một cấp số cộng (arithmetic progression) với公差 (common difference) là 2.
- Vì
rcó thể lên tới 10^9, tuyệt đối không được sử dụng vòng lặp duyệt qua từng phần tử mà phải dùng công thức toán học để tính tổng O(1). - Cần xử lý đúng trường hợp đoạn [l, r] không chứa số lẻ (ví dụ l=2, r=3) để tránh lỗi logic.
Lỗi thường gặp
- Sử dụng biến kiểu
intthay vìlong long: Vớirlên tới 10^9, tổng các số lẻ có thể vượt quá giới hạn của kiểuint(2*10^9), gây tràn số (overflow). - Lỗi chia hết trong công thức: Khi tính
(last - first) / 2hoặc(l + r) * ssh / 2, cần đảm bảo phép chia là số nguyên (vìlast - firstvàsshhoặcl+rđều chẵn). Trong C++, nếu chia hai số nguyên cho nhau, kết quả là số nguyên, nên không sao. Nhưng nếu dùng số thực thì có thể mất độ chính xác. - Quên kiểm tra trường hợp không có số lẻ: Nếu không kiểm tra
if (first > last)hoặc logic tương tự, chương trình có thể tính toán sai (ví dụnbị âm hoặc tính toán lộn xộn).
Bình luận