---
# System prepended metadata

title: 'Đề TS10 - BRVT - 2014: Editorial'

---

# Đề TS10 - BRVT - 2014: 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 2014 - 2015.
>
>**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: (3 điểm)

### Tóm tắt đề bài

Cho hai số nguyên dương $n$ và $x$ $(2 \le n \le 1000,1 \le x \le 9)$. Yêu Cầu:
1. Cho biết chữ số tận cùng của $2^n$.
2. Tính giá trị của các biểu thức sau: 
$$
A = \frac{1}{3}+\frac{2}{4}+\dots+\frac{n-1}{n+1}
$$

$$
B = \frac{x}{1!}+\frac{x^2}{2!}+\dots+\frac{x^n}{n!}
$$

### 1. Cho biết chữ số tận cùng của $2^n$.

**Nhận xét**:
- Nếu $n \equiv 0 \pmod{4}$ thì chữ số tận cùng của $2^n$ là 6.
- Nếu $n \equiv 1 \pmod{4}$ thì chữ số tận cùng của $2^n$ là 2.
- Nếu $n \equiv 2 \pmod{4}$ thì chữ số tận cùng của $2^n$ là 4.
- Nếu $n \equiv 3 \pmod{4}$ thì chữ số tận cùng của $2^n$ là 8.
:::info
**Chứng minh:**
- Vì $2^4 \equiv 6 \pmod{10}$ nên $2^{4k} \equiv 6 \pmod{10}$ $(k \in \mathbb{N}^*)$.
- Xét $2^n$ với $n = 4k+x$: 
$$ 
2^n \equiv 2^{4k+x} \equiv 2^{4k} \times 2^x \equiv 6 \times 2^x \pmod{10}. 
$$
- Thay lần lượt $x \in \{0 \dots 3\}$ vào biểu thức trên sẽ được điều cần chứng minh.
 
**Kiến thức sử dụng:**
- Chữ số tận cùng của một số nguyên dương $a$ là $a \bmod 10$.
- Nếu $a \equiv 6 \pmod{10}$ thì $a^k \equiv 6 \pmod{10}$ $(k \in \mathbb{N}^*)$.
- Mọi số nguyên dương đều có thể viết được dưới dạng $4k+x$ $(k \in \mathbb{N}, x \in \{0 \dots 3\})$.
- $a \times b \equiv (a \bmod c) \times (b \bmod c) \pmod{c}$ $(a,b \in \mathbb{N}; c \in \mathbb{N}^*)$. 
:::

:::spoiler Code
```cpp
int n,x;
cin >> n >> x;

switch (n % 4) {
    case 0: {
        cout << 6;
        break;
    }
    case 1: {
        cout << 2;
        break;
    }
    case 2: {
        cout << 4;
        break;
    }
    case 3: {
        cout << 8;
        break;
    }
}
cout << '\n';
```
:::

### 2. Tính giá trị của biểu thức $A$ và $B$.
**Tính biểu thức $A$**
- Duyệt $i$ từ $1$ đến $n-1$, mỗi lần cộng vào đáp án $\frac{i}{i+2}$.
 
**Tính biểu thức $B$**
- **Ý tưởng**: duyệt $i$ từ $1$ đến $n$, mỗi lần cộng vào đáp án $\frac{x^i}{i!}$ 
- **Vấn đề**: Việc tính riêng tử và mẫu của $\frac{x^i}{i!}$ là không khả thi do vấn đề về giới hạn lớn.
- **Giải pháp**: Gọi $a_i$ là giá trị của số thứ $i$. Dễ dàng nhận thấy $a_i = a_{i-1} \times \frac{x}{i}$ $(1 \le i \le n, a_0 = 1)$. Khi này, với mỗi $i$, tính $a_i$ từ $a_{i-1}$ rồi cộng $a_i$ vào đáp án. 

:::warning
**Lưu ý**: Đáp án là số thực.
:::: 

:::spoiler Code
```cpp
double A = 0;
for (int i = 1; i <= n-1; i++) {
    A += (double)i/(i+2);
}
double B = 0, t = 1;
for (int i = 1; i <= n; i++) {
    t *= (double) x / i;
    B += t;
}
cout << fixed << setprecision(6) << A << ' ' << B << '\n';
```
:::

## Bài 2: (5 điểm)
### Tóm tắt đề bài
Cho hai số nguyên dương $n$, $m$ và dãy nguyên dương $a$ gồm $n$ phần tử $(2 \le n \le 10^5,1 \le m \le 10^9)$. Yêu Cầu:
1. Liệt kê các phần tử có giá trị chẵn trong dãy $a$.
2. Cho biết dãy $a$ có tồn tại số nguyên tố nào không?
3. Cho biết có bao nhiêu cặp số $(i,j)$ thỏa mãn $a_i+a_j$ là số lẻ $(1 \le i \lt j \le n)$.
4. Cho biết giá trị của mẫu số sau khi thực hiện giản ước phân thức sau: $$\frac{a_1 \times a_2 \times \dots \times a_n}{m}$$

### 1. Liệt kê các phần tử có giá trị chẵn trong dãy $a$.
**Nhận xét**: Một số $x$ được gọi là chẵn nếu $x \equiv 0 \pmod{2}$.

:::spoiler Code
```cpp
cin >> n >> m;
for (int i = 1; i <= n; i++) {
    cin >> a[i];
}

for (int i = 1; i <= n; i++) {
    if (a[i] % 2 == 0) {
        cout << a[i] << ' ';
    }
}
cout << '\n';
```
:::

### 2. Cho biết dãy $a$ có tồn tại số nguyên tố nào không?
Đơn giản duyệt qua mọi phần tử trong dãy $a$ và kiểm tra xem có số nguyên tố nào không. Tuy nhiên, vấn đề là làm sao để biết một số có phải số nguyên tố hay không?

**Thuật toán kiểm tra nguyên tố trong $O(\sqrt{n})$.**

**Nhận xét**: 
- Mọi số nguyên dương $x$ đều có thể được phân tích dưới dạng $a \times b$ $(1 \le a,b \le n)$.
- Giả sử $a \le b$, khi này chứng minh được $a \le \sqrt{n}$.
  :::info
  **Chứng minh**: 
  Giả sử $a \gt \sqrt{n}$. Mà $a \le b$, suy ra $b \gt \sqrt{n}$. Khi này $a \times b \gt \sqrt{n} \times \sqrt{n} = n$ (Vô lý). 
  :::
  
Từ nhận xét trên rút ra được thuật toán:
- Nếu $\forall i \in [2, \sqrt{n}],n \not\equiv 0 \pmod{i}$ thì n là số nguyên tố. Ngược lại, n là hợp số.

:::spoiler Code
```cpp
bool check_prime(int x) {
    if (x <= 1) return false;
    int t = sqrt(x);
    for (int i = 2; i <= t; i++) {
        if (x % i == 0) {
            return false;
        }
    }
    return true;
}
```
:::

**Thuật toán kiểm tra nguyên tố trong $O(1)$, chuẩn bị trong $O(n \log{\log{n}})$ (Sàng nguyên tố eratosthenes).**

các bạn có thể tham khảo tài liệu tại đây: 
https://wiki.vnoi.info/algo/algebra/prime_sieve.md.

:::spoiler Code
```cpp
bool isPrime[10005];

void sieve() {
    fill(isPrime,isPrime+10005,true);
    isPrime[0] = isPrime[1] = false;
    int t = sqrt(10000);
    for (int i = 2; i <= t; i++) {
        if (isPrime[i]) {
            for (int j = i * i; j <= 10000; j += i) {
                isPrime[j] = false;
            }
        }
    }
}

bool check_prime(int x) {
    if (x <= 1) return false;
    return isPrime[x];
}
```
:::

Bây giờ đã có 2 thuật toán kiểm tra số nguyên tố, bây giờ việc của ta chỉ cần duyệt qua dãy $a$ rồi thực hiện theo yêu cầu của đề bài.

:::spoiler Code
```cpp
bool prime_exist = false;
for (int i = 1; i <= n; i++) {
    if (check_prime(a[i])) {
        prime_exist = true;
        break;
    }
}
cout << (prime_exist ? "YES" : "NO") << '\n';
```
:::

### 3. Cho biết có bao nhiêu cặp số $(i,j)$ thỏa mãn $a_i+a_j$ là số lẻ.

**Nhận xét**: $a + b$ là số lẻ $\Leftrightarrow$ $a$ và $b$ khác tính chẵn lẻ 

**Ý Tưởng**:
- Duyệt qua mọi i từ $1$ đến $n$, với mỗi $a_i$, ta đếm số lượng $a_j$ $(j \lt i)$ thõa mãn $a_i + a_j \equiv 1 \pmod{2}$. 
- Coi số lẻ là $1$, số chẵn là $0$. $\forall i \in \{1 \dots n\}$, nếu:
  - $a_i$ = 0: Đếm số lượng số $a_j = 1$ $(j \lt i)$ xuất hiện trước đó.
  - $a_i$ = 1: Đếm số lượng số $a_j = 0$ $(j \lt i)$ xuất hiện trước đó.

Việc này có thể có thể dễ dàng thực hiện bằng một mảng đếm.

:::spoiler Code
```cpp
long long pair_count = 0; 
vector<int> cnt(2,0);
for (int i = 1; i <= n; i++) {
    int t = a[i] % 2;
    if (t == 0) {
        pair_count += cnt[1];   
    }
    else {
        pair_count += cnt[0];
    }
    cnt[t]++;
}   
cout << pair_count << '\n';
```
:::

### 4. Cho biết giá trị của mẫu số sau khi thực hiện giản ước phân thức.

Nếu ta tính riêng tử và mẫu sẽ không khả thi vì mỗi $a_i$ có thể lên tới $10^4$ và $n$ lên tới $10^5$ nên giá trị của tử tối đa có thể lên tới $(10^4)^{10^5}$, vượt quá giới hạn của kiểu long long trong **C++**. Vậy nên cần tìm một cách tiếp cận tốt hơn.

**Nhận xét**: Giá trị của mẫu nếu tối giản phân số $\frac{a}{b}$ là $\frac{b}{\gcd(a,b)}$ $(a,b \in \mathbb{N}^*)$.

Vậy việc tính mẫu số sau khi tối giản phân số $\frac{a_1 \times a_2 \times \dots \times a_n}{m}$ tương đương với việc tính $\frac{m}{\gcd(m,a_1 \times a_2 \times \dots \times a_n)}$.

:::spoiler Code
```cpp
for (int i = 1; i <= n; i++) {
    m /= __gcd(m, a[i]);
}
cout << m << '\n';
```
:::

## Bài 3: (2 điểm)
### Tóm tắt đề bài
Dãy $a$ gồm $n$ phần tử được gọi là dãy đặc biệt nếu $\forall i \in \{1, \dots, n\}, a_i = \sum_{j=1}^i 2 \times j$.  

**Ví dụ**: dãy $2,6,12,20$ là dãy đặc biệt, còn dãy $2, 5, 12, 20$ không phải dãy đặc biệt.

**Yêu cầu**: Cho dãy nguyên dương $a$ gồm $n$ phần tử. Hãy cho biết sau khi sắp xếp lại theo thứ tự tăng dần, dãy $a$ có phải dãy đặc biệt không?

### Thuật toán $O(n \log{n})$

Đơn giản chỉ cần sắp xếp lại dãy $a$ tăng dần. Nếu $\forall i \in \{1, \dots, n\}, a_i = \sum_{j=1}^i 2 \times j$ thì $a$ là dãy đặc biệt. Ngược lại, $a$ không phải dãy đặc biệt.

:::spoiler Code
```cpp
cin >> n;
for (int i = 1; i <= n; i++) {
    cin >> a[i];
}
sort(a+1,a+1+n);
long long sum = 0;
for (int i = 1; i <= n; i++) {
    sum += 2 * i;
    if (a[i] != sum) {
        cout << 0;
        return 0;
    }
}
for (int i = 1; i <= n; i++) {
    cout << a[i] << '\n';
}
```
:::

Độ phức tạp cho việc sắp xếp là $O(n \log{n})$ và việc kiểm tra dãy $a$ có độ phức tạp $O(n)$. Vậy tựu chung thuật toán có độ phức tạp $O(n \log{n})$.

### Thuật toán $O(n)$

**Nhận xét**: Nếu $k$ là số đặc biệt thì $\exists \;i \in \mathbb{N}^*, \; k = i \times (i + 1)$.

:::info
Chứng minh:
Vì k là số đặc biệt nên k có dạng $2 + 4 + \dots + 2 \times i$ $(i \in \mathbb{N}^*)$.
Nhận thấy $2 + 4 + \dots + 2 \times i$ là tổng của một dãy số cách đều không giảm. 
Áp dụng công thức tính tổng dãy số cách đều có quy luật:
$$
\text{Tổng} = \frac{(\text{Số đầu} + \text{Số cuối}) \times \text{Số số hạng}}{2}
$$

$$
\text{Số số hạng} = \frac{(\text{Số cuối} - \text{Số đầu})}{\text{Khoảng cách}} + 1
$$
Khi này:
Số số hạng của dãy là $\frac{(2 \times i - 2)}{2} + 1$.
Tổng của dãy là $\frac{(2 + 2 \times i) \times ( \frac{2 \times i - 2}{2} + 1)}{2} = i \times (i + 1)$.
:::
  
Để tính được $i$ nhanh, ta có thể biến đổi lại như sau: 

$$
k = i \times (i + 1) \Rightarrow i^2 + i - k = 0 \; (*)
$$

Đến đây ta sử dụng công thức nghiệm cho phương trình bậc 2:

:::info
Công thức nghiệm cho phương trình bậc 2 có dạng $ax^2 + bx + c = 0 \;(a \not= 0)$:
$$
\Delta = b^2 - 4ac
$$

Trường hợp 1: Nếu $\Delta \lt 0$, phương trình vô nghiệm
Trường hợp 2: Nếu $\Delta \ge 0$, phương trình có 2 nghiệm:
$$
x = \frac{-b \pm \sqrt{\Delta}}{2a}
$$
:::

Ta có: 
$$
\Delta = 1 + 4k
$$

Vì $k \in \mathbb{N}^*$ nên $\Delta > 0$, phương trình luôn có nghiệm. Nên:
$$
i = \frac{-1 \pm \sqrt{1+4k}}{2}
$$

Mà $i \ge 0$. Nên:
$$
i = \frac{-1 + \sqrt{1+4k}}{2}
$$

Vậy $\frac{-1 + \sqrt{1+4k}}{2}$ là một số nguyên dương thì k là số đặc biệt. Ngược lại, k không phải số đặc biệt.

**Ý tưởng**:
- Với mỗi $a_i$, tìm số $x$ thõa mãn $a_i = x \times (x + 1)$. Nếu $x \not\in \mathbb{N}^*$ hoặc $\exists \; j < i, \; a_j = x \times (x + 1)$, dãy $a$ không phải dãy đặc biệt. Ngược lại là đánh dấu lại $x$ bằng một mảng đánh dấu. 
- Duyệt qua mảng đánh dấu từ $1$ tới $n$, nếu tồn tại số chưa được đánh dấu thì dãy $a$ không phải dãy đặc biệt. Ngược lại dãy $a$ là dãy đặc biệt.

:::spoiler Code
```cpp
#include<bits/stdc++.h>
using namespace std;

const int N = 1e6+5;

int n;
bool mark[N];

main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        long long a;
        cin >> a;
        if (a > 1LL * 1e6 * (1e6 + 1)) {
            cout << 0;
            return 0;
        }
        int t = (sqrt(4*a+1) - 1) / 2;
        if (1LL * t * (t + 1) != a || mark[t]) {
            cout << 0;
            return 0;
        }
        mark[t] = true;
    }
    for (int i = 1; i <= n; i++) {
        if (!mark[i]) {
            cout << 0;
            return 0;
        }
    }
    for (int i = 1; i <= n; i++) {
        cout << 1LL * i * (i + 1) << '\n';
    }
}
```
:::


