# Đề TS10 - BRVT - 2017: Editorial >[!Note] Thông tin >Sau đây là lời giải của Kỳ thi Tuyển sinh 10 trường THPT chuyên Lê Quý Đôn tỉnh Bà Rịa - Vũng Tàu năm học 2017 - 2018. > >**Bạn đọc có thể nộp và chấm bài (test tự sinh)** [TẠI ĐÂY](https://chuyentin-brvt.online/contest/algi_ts10_15_24). > >:::info >Chuẩn bị bởi ==team Logica==, thuộc khuôn khổ dự án [**The Algitect (ALGI Project)**](https://www.facebook.com/algitect.project) >::: [toc] ## Bài 1 ### Tóm tắt đề bài Nhập vào số nguyên dương $N$. **Yêu cầu:** Tính kết quả các biểu thức sau: - $A = \frac{1}{2} + \frac{2}{2^2} + \frac{3}{2^3} + \dots + \frac{N}{2^N}$ - $B = \frac{1 \times 2}{3 \times 4} + \frac{3 \times 4}{5 \times 6} + \frac{5 \times 6}{7 \times 8} + \dots + \frac{(2N - 3)(2N - 2)}{(2N - 1)2N}$ **Dữ liệu đảm bảo:** $2 \le N \le 100$. ### **Tính A** Cho biến $i$ chạy vòng lặp từ $1$ đến $n$, cộng ==$\frac{i}{2^i}$== vào kết quả. >[!Caution] Lưu ý > Để tránh số quá lớn, ta nên lấy $i$ và chia liên tục cho $2$ thay vì tính $2^i$ **Độ phức tạp thời gian:** $O\left(n\right)$. ### **Tính B** Cho biến $i$ chạy vòng lặp từ $2$ đến $n$, cộng ==$\frac{(2i - 3)\times(2i -2)}{2i}$== vào kết quả. **Độ phức tạp thời gian:** $O\left(n\right)$. ### **Mã nguồn mẫu** :::info Độ phức tạp thời gian của cả bài toán là ==tổng độ phức tạp thời gian== của từng yêu cầu. ::: :::success :::spoiler Code ```cpp = 1 #include <bits/stdc++.h> using namespace std; int main() { int n; double A = 0, B = 0; cin >> n; for (int i = 1; i <= n; i++) { double ret = i; for (int j = 1; j <= i; j++) { ret /= 2; } A += ret; if (i >= 2) { B += (double)(2*i - 3)*(2*i - 2) / (2*i - 1) / (2*i); } } cout << fixed << setprecision(3) << A << "\n" << B; return 0; } ``` ::: ## Bài 2: ### Tóm tắt đề bài Nhập vào $3$ số nguyên dương $a, b$ và $N$. **Yêu cầu:** - Tìm các **số nguyên tố** nằm trong đoạn $[a, b]$. - Tìm **chữ số chẵn lớn nhất** của $N$. **Dữ liệu đảm bảo:** $2 \le a < b \le 2 \times 10^5$ và $1 \le N \le 10^{18}$ ### **Yêu cầu 1** Duyệt qua các số từ $a$ đến $b$, kiểm tra tính nguyên tố của mỗi số bằng cách ==duyệt đến căn bậc hai== của số đó để tìm ước. **Độ phức tạp thời gian:** $O \left( \sqrt a + \sqrt {a+1} + \dots + \sqrt b \right) = O\left( \sum_{i = a}^b \sqrt i \right)$. ### **Yêu cầu 2** Duyệt qua các chữ số của $n$ để tìm ==chữ số chẵn lớn nhất==. Có thể thực hiện bằng cách không ngừng lấy chữ số tận cùng của $n$ là $n \bmod 10$, sau đó ta ==chia $n$ cho $10$== để xóa chữ số đó đi và tìm chữ số tiếp theo. **Độ phức tạp thời gian:** $O\left( \log_{10} n \right)$. ### **Mã nguồn mẫu** :::info Độ phức tạp thời gian của cả bài toán là ==tổng độ phức tạp thời gian== của từng yêu cầu. ::: :::success :::spoiler Code ```cpp = 1 #include <bits/stdc++.h> using namespace std; bool isPrime(int x) { if (x < 2) { return 0; } for (int i = 2; i * i <= x; i++) { if (x % i == 0) { return 0; } } return 1; } int main() { int a, b; long long n; cin >> a >> b >> n; for (int i = a; i <= b; i++) { if (isPrime(i)) { cout << i << " "; } } int res = -1; do { if ((n % 10) % 2 == 0) { res = max(res, n % 10); } } while (n /= 10); cout << "\n" << res; return 0; } ``` ::: ## Bài 3: ### Tóm tắt đề bài Cho dãy số nguyên gồm $N$ phần tử $a_1, a_2, \dots, a_N$ và số nguyên $X$. **Yêu cầu:** - Liệt kê các phần tử **dương** có dạng ==$5 \times k$ (với $k$ là số nguyên bất kỳ)== theo thứ tự ban đầu của dãy. - Tìm **tích lớn nhất** của hai phần tử bất kỳ trong dãy (không trùng nhau). - Sắp xếp dãy **tăng dần** và thực hiện chèn thêm một phần tử có giá trị $X$ vào dãy sao cho vẫn giữ nguyên tính chất **tăng dần** của dãy số. **Dữ liệu đảm bảo:** - $2 \le N \le 10^5$. - $|a_i| \le 10^6$. - $|X| \le 2 \times 10^6$ ### **Yêu cầu 1** >[!Tip] Nhận xét >$$ >A_i = 5k \Leftrightarrow 5k = A_i \Leftrightarrow k = \frac {A_i}{5} >$$ > Mà $k$ nguyên, do đó $A_i$ chia hết cho $5$, hay ==$A_i \bmod 5 = 0$==. Như vậy, ta duyệt qua dãy và in ra các số thỏa mãn điều kiện trên. **Độ phức tạp thời gian:** $O \left( n \right)$. ### **Yêu cầu 2** >[!Tip] Nhận xét > Dễ nhận thấy, ==hai số lớn nhất== của dãy sẽ tạo ra tích lớn nhất. > :::danger > **Lưu ý:** ==Hai số bé nhất (cùng âm)==, khi nhân vào sẽ tạo ra tích dương, và có thể lớn hơn tích của hai số lớn nhất. > ::: Sắp xếp dãy tăng dần, ta có: - Hai số lớn nhất là $A_N$ và $A_{N-1}$. - Hai số nhỏ nhất là $A_1$ và $A_2$. **Đáp án:** ==$\max(A_N \times A_{N-1}, A_1 \times A_{2})$==. **Độ phức tạp thời gian:** $O(n \log n)$ do thao tác sắp xếp mảng. ### **Yêu cầu 3** Để giữ nguyên tính chất tăng dần của dãy, ta cần chèn $x$ vào giữa hai vị trí ==$i$ và $i+1$== sao cho ==$A_i \le x \le A_{i+1}$==. **Độ phức tạp thời gian:** $O(n)$. ### **Yêu cầu 4** >[!Note]Nhận xét: >Chênh lệch giữa hai phần là lớn nhất khi một phần đạt tổng lớn nhất có thể và phần còn lại phải nhỏ nhất có thể. >Dễ dàng nhận thấy, >- Nếu $k \ge n-k$, ta nhóm ==$k$ phần tử lớn nhất== chung với nhau và ==$n-k$ phần tử nhỏ nhất== chung với nhau >- Nếu $k \lt n-k$, ta nhóm ==$n-k$ phần tử lớn nhất== chung với nhau và ==$k$ phần tử nhỏ nhất== chung với nhau Có thể tìm nhanh tập các phần tử lớn nhất hoặc nhỏ nhát bằng cách sắp xếp lại dãy số. Để dễ thao tác, ta ==không thực sự chèn số vào==, mà ta sẽ duyệt qua dãy và in ra các số, nếu đúng vị trí của $x$ ta sẽ in ra $x$. >[!Caution] Lưu ý > Trường hợp $x$ lớn hơn tất cả các số trong dãy, ta phải thêm $x$ vào cuối. **Độ phức tạp thời gian:** $O(n)$ vì dãy đã được sắp xếp sẵn ở yêu cầu trước. ### **Mã nguồn mẫu** :::info Độ phức tạp thời gian của cả bài toán là ==tổng độ phức tạp thời gian== của từng yêu cầu. ::: :::success :::spoiler Code ```cpp = 1 #include <bits/stdc++.h> using namespace std; const int N = 1e5; int n, X, A[N+1]; int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> A[i]; } cin >> X; for (int i = 1; i <= n; i++) { if (A[i] > 0 && A[i] % 5 == 0) { cout << A[i] << " "; } } sort(A+1, A+1+n); cout << "\n" << max(1LL * A[1] * A[2], 1LL * A[n-1] * A[n]) << "\n"; bool used = 0; for (int i = 1; i <= n; i++) { if (X <= A[i] && !used) { used = 1; cout << X << " "; } cout << A[i] << " "; } if (!used) { cout << X << " "; } return 0; } ``` ::: ## Bài 4: ### Tóm tắt đề bài Có $N$ cây xanh xếp thành một hàng thẳng, lần lượt cách cổng trường THPT chuyên Lê Quý Đôn $a_1, a_2, \dots, a_N$. Bóng của chúng cũng thẳng hàng và bóng của cây thứ $i$ có chiều dài là $d_i$. **Yêu cầu:** Tính tổng chiều dài của các bóng cây phủ trên đường. > Lưu ý: Nếu có vùng bị phủ bóng bởi nhiều hơn một cây, chỉ xem vùng đó là một. **Dữ liệu đảm bảo:** $1 \le N \le 10^5$, $0 < a_i \le 10^6$ và $0 < d_i \le 10^3$. ### Lời giải >[!Tip] Mô hình hóa bài toán > Dễ thấy, cây thứ $i$ cho ta vùng bóng ==$[a_i, a_i + d_i - 1]$==. > Với mỗi vùng tương ứng của từng cây, ta cộng tất cả phần tử trong khoảng lên $1$. Để cộng nhanh từng đoạn, ta áp dụng [**mảng hiệu**](https://wiki.vnoi.info/algo/data-structures/prefix-sum-and-difference-array.md). **Độ phức tạp thời gian:** $O(n)$. ### **Mã nguồn mẫu** :::success :::spoiler Code ```cpp = 1 #include <bits/stdc++.h> using namespace std; const int N = 5e6; int n, F[N+1]; int main() { cin >> n; for (int i = 1; i <= n; i++) { int x, y; cin >> x >> y; for (int j = x; j <= x+y-1; j++) F[j]++; } int res = 0; for (int i = 1; i <= N; i++) if (F[i]) res++; cout << res; return 0; } ``` :::