---
# System prepended metadata

title: 'HSG9 - BRVT - 2015: Editorial'

---

# Đề HSG9 - BRVT - 2015: Editorial

## Bài 1: Thừa kế (7 điểm)

Tính tổng các số chẵn và tổng các số lẻ trong đoạn $\left[ a, b \right]$ $\left( a, b \le 10^9 \right)$

:::info
:information_source: Ký hiệu toán học cần biết:

$\lceil \frac{a}{b} \rceil$: Phép tính $\frac{a}{b}$ làm tròn lên.
$\lfloor \frac{a}{b} \rfloor$: Phép tính $\frac{a}{b}$ làm tròn xuống

${\sum_{i=a}^b i}$ : Tổng các số từ a đến b
:::

### Brute - force:

Duyệt tuần tự từ a đến b và cộng các số chẵn hoặc lẻ vào tổng tương ứng.

Độ phức tạp thời gian: $O \left( b - a + 1 \right)$.

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

int main() {
    int sumOdd = 0, sumEven = 0;
    for (int i = a; i <= b; i++) {
        if (i % 2 == 0) {
            sumEven += i;
        }
        else {
            sumOdd += i;
        }
    }

    if (sumEven > sumOdd) {
        cout << 1 << "\n";
    }
    else {
        cout << 2 << "\n";
    }

    cout << abs(sumEven - sumOdd);
    
    return 0;
}
```
:::

### Accepted:

Xét đoạn $\left[ a, b \right]$, đặt:

- $sE$: Tổng các số chẵn.
- $sO$: Tổng các số lẻ.
- $sTotal$: Tổng các số.

Ta có ==$sO = sTotal - sE$==. Vậy chỉ cần tính **$sE$** và **$sTotal$**!

$$
\begin{flalign}
sTotal 
&= \sum_{i=a}^b i \\
&= \sum_{i=1}^b i - \sum_{i=1}^{a-1} i \\
&= \frac{b(b+1)}{2} - \frac{(a-1)a}{2}
\end{flalign}
$$

>Tổng các số từ $a$ đến $b$ bằng tổng các số từ $1$ đến $b$ trừ đi tổng các số từ $1$ đến $a-1$

Những số chẵn trong đoạn $\left[ a, b \right]$ có thể viết lại thành $2i$ với $\lceil \frac{a}{2} \rceil \le i \le \lfloor \frac{b}{2} \rfloor$

$$
\begin{flalign}
sE
&= \sum_{i=\lceil \frac{a}{2} \rceil}^{\lfloor \frac{b}{2} \rfloor} 2i \\
&= 2 * \sum_{i=\lceil \frac{a}{2} \rceil}^{\lfloor \frac{b}{2} \rfloor} i \\ 
&= 2 * \left( \sum_{i=1}^{\lfloor \frac{b}{2} \rfloor} i - \sum_{i=1}^{\lceil \frac{a}{2} \rceil - 1} i \right) \\
&= 2 * \left( \frac{{\lfloor \frac{b}{2} \rfloor}({\lfloor \frac{b}{2} \rfloor}+1)}{2} - \frac{({\lceil \frac{a}{2} \rceil}-1){\lceil \frac{a}{2} \rceil}}{2} \right)
\end{flalign}
$$

>sE được tính bằng cách lấy tổng các số từ $\lceil \frac{a}{2} \rceil$ đến $\lfloor \frac{b}{2} \rfloor$ nhân đôi lên

Sau khi đã tính được $sE$ và $sTotal$, ta tính $sO$. Như vậy, bài toán đã được giải quyết!

>VD: Trong đoạn $\left[ 3, 10 \right]$ có những số chẵn sau: $4, 6, 8, 10$.
>Tương ứng với: $2*2, 2*3, 2*4, 2*5$.
>
>$sTotal = \frac{10*(10+1)}{2} - \frac{(3-1)*3}{2} = 52$
>
>${\lfloor \frac{a}{2} \rfloor} = {\lfloor \frac{10}{2} \rfloor} = 5$
>${\lceil \frac{b}{2} \rceil} = {\lceil \frac{3}{2} \rceil} = 2$
>
>$sE = 2 * \left( \frac{5*(5+1)}{2} - \frac{(2-1)*2}{2} \right) = 28$
>
>$sO = sTotal - sE = 52 - 28 = 24$

Độ phức tạp thời gian: $O \left( 1 \right)$.

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

int main() {
    long long a, b;
    cin >> a >> b;
    
    long long l = (a + 1) / 2, r = b / 2;

    //Lấy max với 0 phòng trường hợp l = r
    long long sE = max(0LL, (r * (r + 1) / 2 - l * (l - 1) / 2) * 2);

    long long sTotal = b * (b + 1) / 2 - a * (a - 1) / 2;

    long long sO = sTotal - sE;

    if (sE > sO) {
        cout << 1 << "\n";
    }
    else {
        cout << 2 << "\n";
    }

    cout << abs(sE - sO);
    
    return 0;
}
```
:::

## Bài 2: Chọn quà (7 điểm)

Cho dãy số nguyên dương $A_1, A_2, A_3, \dots, A_n$ $\left( n \le 10^6 \right)$.
Đếm số cách chọn cặp $A_i, A_j$ $\left( i < j \right)$ sao cho **tổng các số còn lại là chẵn**.

### Brute - force:

Tính trước tổng của dãy số và lưu vào biến $sum$.

Duyệt tuần tự để cố định $A_i$, tương ứng với mỗi giá trị lại duyệt tuần tự một lần nữa để tìm $A_j$. Kiểm tra nhanh cặp số hiện tại có thỏa mãn hay không bằng cách kiểm tra $sum - \left( A_i + A_j \right)$ có chẵn hay không.

Độ phức tạp thời gian: $O \left( b - a + 1 \right)$.

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

int main() {
    long long sum = 0;
    for (int i = 1; i <= n; i++) {
        sum += A[i];
    }

    int res = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            if ( (sum - (A[i] + A[j]) ) % 2 == 0) {
                res++;
            }
        }
    }

    cout << res;
    
    return 0;
}
```
:::

### AC:

Nhận thấy tính chẵn lẻ của $sum - (A_i + A_j)$ phụ thuộc vào tính chẵn lẻ của $(A_i + A_j)$ do $sum$ đã cố định, ta có thể chia ra các trường hợp như sau:

#### Trường hợp 1: $sum$ chẵn $\to$ $\left( A_i + A_j \right)$ phải chẵn.

Bài toán quy về **"Đếm số cặp số có tổng chẵn"**, chỉ có hai trường hợp như sau: 

- Chẵn - Chẵn.
- Lẻ - Lẻ.

#### Trường hợp 2: $sum$ lẻ $\to$ $\left( A_i + A_j \right)$ phải lẻ.

Bài toán quy về **"Đếm số cặp số có tổng lẻ"**, chỉ có duy nhất trường hợp sau: 

- Chẵn - Lẻ.

---

Như vậy để xử lý bài toán chỉ cần đếm số lượng số chẵn và số lẻ trong dãy.

Khi đó, đặt:

- $cnt_0$: số lượng số chẵn.
- $cnt_1$: số lượng số lẻ.

Ta có các công thức tính như sau:

- Số cặp chẵn - chẵn: $\frac {cnt_0 \cdot (cnt_0 - 1)}{2}$.
- Số cặp lẻ - lẻ: $\frac {cnt_1 \cdot (cnt_1 - 1)}{2}$
- Số cặp chẵn - lẻ: $cnt_0 \cdot cnt_1$

Độ phức tạp thời gian: $O \left( n \right)$.

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

int main() {
    int n, x;
    long long res = 0, sum = 0, cnt[2] = {0, 0};

    cin >> n;
    for (int i = 0; i < n; i++) {
        int x; 
        cin >> x;
        
        sum += x;
        cnt[x % 2]++;
    }

    if (sum % 2 == 0) {
        cout << cnt[0] * (cnt[0] - 1) / 2 + cnt[1] * (cnt[1] - 1) / 2;
    }
    else {
        cout << cnt[0] * cnt[1];
    }
    
    return 0;
}
```
:::

## Bài 3: Đổ nước vào chai (6 điểm)

Cho dãy số nguyên dương $A_1, A_2, A_3, ..., A_n$ $(n \le 10^5)$. Chọn một số phần tử sao cho không có hai phần tử nào liền kề nhau trong dãy, sao cho tổng các phần tử được chọn là **lớn nhất**.

### Brute - force:

Quay lui thử tất cả các cách chọn.

Độ phức tạp thời gian: $O\left( 2^n \right)$.

### AC:

Quy hoạch động cơ bản.

Định nghĩa $dp_i$ là tổng lớn nhất có thể đạt nếu xét lấy trong $i$ phần tử đầu tiên (có thể lấy hoặc không lấy).

Công thức quy hoạch động: 

- $dp_1$ = $A_1$: Trường hợp cơ sở.
- $dp_i = \max(dp_{i-1}, \: dp_{i-2} + A_i)$ $\left( i \ge 2 \right)$:
    - $dp_i = dp_{i-1}$: Không lấy $A_i$ vào tổng tối ưu.
    - $dp_i = dp_{i-2} + A_i$: Lấy $A_i$ vào tổng tối ưu.

Kết quả: $dp_n$.

Độ phức tạp thời gian: $O \left( n \right)$.

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

const int N = 1e5;
int n, A[N+1];
long long dp[N+1];

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> A[i];
    }

	dp[1] = A[1];
	for (int i = 2; i <= n; i++)  {
		dp[i] = max(dp[i-1], dp[i-2] + A[i]);
    }

	cout << dp[n];

	return 0;
}
```
:::