# Đề TS10 - BRVT - 2016: 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 2016 - 2017.
>
>**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
Cho số nguyên dương $n$.
**Yêu cầu:**
- Cho biết $n$ có phải số chẵn không
- Tính các biểu thức sau:
\begin{align}
&A = \prod_{i=3}^{n} \frac{1}{i \cdot(i-1)} \\
&B = \sum_{i=1}^{n} \frac{2 \cdot i-1}{2 \cdot i+1}
\end{align}
### Kiểm tra tính chẵn lẻ
Nếu $n$ chia hết cho $2$ thì $n$ chẵn, ngược lại $n$ lẻ. Sử dụng ==phép toán $\bmod$== để kiểm tra.
**Độ phức tạp thời gian:** $O \left( 1 \right)$
### Tính biểu thức A
Khởi gán $A = 0$. Duyệt qua mọi $i \in [3,n]$ và cộng ==$\frac{1}{i \cdot (i-1)}$== vào $A$.
**Độ phức tạp thời gian:** $O \left( n \right)$
### Tính biểu thức B
Khởi gán $B = 0$. Duyệt qua mọi $i \in [1,n]$ và cộng ==$\frac{2 \cdot i-1}{2 \cdot i+1}$== vào $B$.
**Độ phức tạp thời gian:** $O \left( n \right)$
:::danger
Lưu ý: Vì bài toán liên quan đến số thực. Vậy nên cần sử dụng kiểu dữ liệu double hoặc long double để đảm bảo độ chính xác.
:::
:::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
#include<bits/stdc++.h>
using namespace std;
int n;
double A, B;
int main() {
cin >> n;
for (int i = 3; i <= n; i++) {
A += (double)1/((i-1)*i);
}
for (int i = 1; i <= n; i++) {
B += (double)(2*i-1)/(2*i+1);
}
cout << (n & 1 ? "NO" : "YES") << '\n' << fixed << setprecision(2) << A << '\n' << B;
return 0;
}
```
:::
## Bài 2
### Tóm tắt đề bài
Cho $2$ số nguyên dương $a$ và $b$.
**Yêu cầu:**
- Tối giản phân số $\frac{a}{b}$.
- Đếm số lượng số chia hết cho $3$ trong đoạn $[a,b]$.
### Tối giản phân số
Để tối giản $\frac{a}{b}$, ta chia $a$ và $b$ cho $\operatorname{UCLN}(a,b)$.
:::info
C++ cung cấp sẵn hàm `gcd()` để tìm UCLN của hai số.
:::
**Độ phức tạp thời gian:** $O \left( \log \min(a, b) \right)$
> Độ phức tạp của hàm `gcd()` trong C++ STL.
### Đếm số lượng số chia hết cho 3 trong đoạn
>[!Tip]
> Số lượng số ==chia hết cho $x$== từ $1$ đến $n$ là: ==$\lfloor \frac{n}{x} \rfloor$==
Gọi $f(x)$ là số lượng số chia hết cho $3$ trong đoạn $[1,x]$. Khi này, $f(x) = \lfloor \frac{x}{3} \rfloor$.
**Đáp án:** %f(b) - f(a-1)$.
**Độ phức tạp thời gian:** $O \left( 1 \right)$
:::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
#include<bits/stdc++.h>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
int gcd = __gcd(a,b);
cout << a / gcd << '/' << b / gcd << '\n' << b / 3 - (a - 1) / 3;
return 0;
}
```
:::
## Bài 3:
### Tóm tắt đề bài
Cho dãy số nguyên dương gồm $n$ phần tử $a_1, a_2, \dots, a_n$.
- Liệt kê các phần tử có ==dạng $3k+2$==.
- Tìm số có ==giá trị lớn nhất== của dãy.
- Tìm số có ==giá trị nhỏ nhất== của dãy.
### Liệt kê các phần tử có dạng $3k+2$
Một số nguyên dương $x$ có dạng $3k+2$ khi $x \equiv 2 \pmod{3}$ hay $x - 2 \equiv 0 \pmod{3}$.
> Nghĩa là ==$x \bmod 3 = 0$==.
Do đó, ta duyệt qua mọi phần tử và in ra các phần tử thỏa mãn điều kiện trên.
**Độ phức tạp thời gian:** $O \left( n \right)$
### Tìm số có giá trị lớn nhất của dãy.
Gọi $f_{max}$ là giá trị lớn nhất của dãy.
- Khởi gán ==$f_{max} = -\infty$==.
- Duyệt qua mọi $i \in [1,n]$, ==nếu $f_{max} \lt a_i$ thì gán $f_{max} = a_i$==.
**Độ phức tạp thời gian:** $O \left( n \right)$
### Tìm số có giá trị nhỏ nhất của dãy.
Gọi $f_{min}$ là giá trị lớn nhất của dãy.
- Khởi gán ==$f_{min} = \infty$==.
- Duyệt qua mọi $i \in [1,n]$, ==nếu $f_{min} \gt a_i$ thì gán $f_{min} = a_i$==.
**Độ phức tạp thời gian:** $O \left( n \right)$
:::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
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
for (auto& x : a) {
cin >> x;
}
for (auto& x : a) {
if ((x - 2) % 3 == 0) {
cout << x << ' ';
}
}
cout << '\n' << *max_element(a.begin(),a.end()) << '\n' << *min_element(a.begin(),a.end());
return 0;
}
```
:::
## Bài 4
### Tóm tắt đề bài
Cho dãy nguyên dương gồm $n$ phần tử $a_1, a_2, \dots, a_n$.
Gọi $S_1$ là tổng các đồ vật từ $1$ đến $k$ và $S_2$ là tổng các đồ vật từ $k+1$ đến $n$ $(1 \le k \lt n)$.
**Yêu cầu:** Tìm cách chia sao cho ==$S_1 \cdot S_2$ lớn nhất==.
### Lời giải
Áp dụng ==prefix sum (mảng cộng dồn) cơ bản==.
Gọi $f_i = \sum_{j=1}^{i} a_j$ (tổng $i$ số đầu tiên của mảng).
Khi này, ta có:
- Tổng của các phần tử trong ==đoạn $[1,k]$== là ==$S_1 = f_k$==.
- Tổng các phần tử trong ==đoạn $[k+1,n]$== là ==$S_2 = f_n - f_{k}$==.
Duyệt qua mọi $i \in [1,n)$ và tìm vị trí $i$ để $f_i \cdot (f_n - f_i)$ lớn nhất.
**Độ phức tạp thời gian:** $O \left( n \right)$
:::success
:::spoiler Code
```cpp
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<long long> f(n+5,0);
for (int i = 1; i <= n; i++) {
int a;
cin >> a;
f[i] = f[i-1] + a;
}
long long ans = 0;
array<int,2> f;
for (int i = 1; i < n; i++) {
long long v = f[i] * (f[n] - f[i]);
if (ans < v) {
ans = v;
f = {f[i], f[n] - f[i]};
}
}
cout << f[0] << ' ' << f[1];
return 0;
}
```
:::