# Đề THT B - BRVT - 2022: Editorial
>[!Note] Thông tin
>Sau đây là lời giải của Kỳ thi Tin học trẻ bảng B tỉnh Bà Rịa - Vũng Tàu năm học 2021 - 2022.
>
>**Bạn đọc có thể nộp và chấm bài (test tự sinh)** [TẠI ĐÂY](https://chuyentin-brvt.online/contest/algi_thtb_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ích nguyên tố (40 điểm)
### Tóm tắt đề bài
Cho số nguyên dương $n$.
**Yêu cầu:** Tìm hai số nguyên tố ==khác nhau== thỏa mãn tích của chúng là ==lớn nhất== và tích đó không được vượt quá $n$.
### Lời giải
>[!Tip]Tính chất 1
>Với mọi số nguyên dương $n$ luôn tồn tại hai số nguyên dương $a, b$ thỏa $n = a \times b$.
>
> Không mất tính tổng quát, giả sử ==$a \le b$==. Khi đó ta có:
> - $a \le \sqrt n$.
> - $b \ge \sqrt n$.
>[!Tip]Tính chất 2
> Xét trong khoảng $10^9$ trở lại, cứ không quá $200$ số nguyên liên tiếp, chắc chắn sẽ tồn tại một số nguyên tố.
Duyệt số nguyên tố $a$ từ $1$ đến $n$ và tìm số nguyên tố $b$ lớn nhất có thể thỏa mãn đề bài.
Ta biết: $a \times b \le n$, tức là $b \le \frac{n}{a}$. Như vậy, có thể duyệt $b$ giảm dần từ $\frac{n}{a}$ đến $\frac{n}{a} - 200$, nếu $b$ là số nguyên tố thì lấy kết quả và chuyển tới số $a$ tiếp theo.
**Độ phức tạp thời gian**: $O\left(\sqrt n \times 200 \times \sqrt n \right)$.
> Tuy nhiên, độ phức tạp thực tế thâp hơn nhiều, do các trường hợp ta tìm được $b$ sớm, và khi kiểm tra tính nguyên tố ta cũng có không cần duyệt hết căn của số đó.
:::success
:::spoiler Code
```cpp = 1
#include <bits/stdc++.h>
using namespace std;
int n;
bool isPrime[32000];
bool Prime(int x) {
for (int i = 2; i*i <= x; i++)
if (x % i == 0) return false;
return true;
}
int main(){
cin >> n;
for (int i = 2; i*i <= n; i++) {
isPrime[i] = true;
}
for (int i = 2; i*i*i*i <= n; i++) {
if (isPrime[i] == true) {
for (int j = i*i; j*j <= n; j += i) {
isPrime[j] = false;
}
}
}
int MaxVal = 0, a, b;
for (int i = 2; i*i <= n; i++) {
if (isPrime[i] == true) {
int lim = n / i;
for (int j = lim; j >= 1; j--) {
if (Prime(j)) {
if (i * j < MaxVal || i == j) break;
MaxVal = i * j;
a = i;
b = j;
}
}
}
}
cout << a << ' ' << b;
return 0;
}
```
:::
## Bài 2: Giao lưu (30 điểm)
### Tóm tắt đề bài
Tại mỗi thời điểm, dữ liệu cho số $0$ tương ứng với có $1$ học sinh đi ra khỏi trường, và số $1$ nếu có $1$ học sinh đi vào trường.
**Yêu cầu:** Tính số học sinh ở trong trường nhiều nhất tại $1$ thời điểm.
### Lời giải
Gọi $cur$ là số học sinh đang có trong trường.
Ta duyệt qua từng thời điểm:
- Nếu có học sinh ra khỏi trường (số $0$) $\rightarrow$ $cur = cur - 1$.
- Nếu có học sinh đi vào trường (số $1$) $\rightarrow$ $cur = cur + 1$.
**Đáp án:** Giá trị lớn nhất của $cur$ tại mọi thời điểm.
**Độ phức tạp thời gian:** $O(n)$
:::success
:::spoiler Code
```cpp = 1
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
int cur = 0, res = 0;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
if (x == 0) cur--;
else cur++;
res = max(res, cur);
}
cout << res;
return 0;
}
```
:::
## Bài 3: Đội tuyển Tin học (30 điểm)
### Tóm tắt đề bài
Có $n$ học sinh, cho biết thời gian luyện tập của học sinh thứ $i$ là từ $l_i$ đến $r_i$.
Thời gian luyện tập hiệu quả là thời gian mà chỉ có duy nhất một học sinh đang luyện tập.
**Yêu cầu:** Hãy chọn ra 1 số học sinh từ $n$ học sinh trên sao cho tổng thời gian luyện tập hiệu quả là lớn nhất.
### Lời giải:
Áp dụng ==quy hoạch động==.
>[!Important] Thứ tự quy hoạch động
>Để có thứ tự quy hoạch động, ta cần sắp xếp các học sinh lại theo thứ tự tăng dần của thời gian kết thúc giờ luyện tập ($r_i$ tăng dần).
- **Định nghĩa:** ==$f_i$== là thời gian luyện tập hiệu quả nhiều nhất nếu chọn một số học sinh trong $i-1$ học sinh trước đó và chắc chắn chọn học sinh $i$.
- **Khởi gán:** ==$f_i = r_i - l_i$== (trường hợp chỉ lấy học sinh $i$).
- **Công thức:** (nếu lấy học sinh thứ $i$ xếp vào ngay sau học sinh $j$)
$$
f_i = \max \left(f_i, f_j - \max(0, r_j - l_i) + r_i - \max(r_j, l_i) \right)
$$
> **Trong đó**:
> - $r_j - l_i$ là khoảng thời gian học không hiệu quả.
> - $r_i - \max(r_j, l_i)$ là khoảng thời gian học tập hiệu quả của học sinh $i$.
**Đáp án:** $\max(f_i) \; \forall \; i$.
**Độ phức tạp thời gian**: $O(n^2)$.
:::success
:::spoiler Code
```cpp = 1
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
int n, f[N];
struct students {
int L, R;
} a[N];
bool cmp(const students &a, const students &b) {
return a.R < b.R;
}
int main(){
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].L >> a[i].R;
}
sort (a + 1, a + 1 + n, cmp);
int res = 0;
for (int i = 1; i <= n; i++) {
f[i] = a[i].R - a[i].L;
for (int j = 1; j < i; j++) {
f[i] = max(f[i], f[j] - max(0, a[j].R - a[i].L) + a[i].R - max(a[j].R, a[i].L));
}
res = max(res, f[i]);
}
cout << res;
return 0;
}
```
:::