Try   HackMD

Đề 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

[a,b]
(a,b109)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Ký hiệu toán học cần biết:

ab: Phép tính
ab
làm tròn lên.
ab
: Phép tính
ab
làm tròn xuống

i=abi : 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(ba+1).

Code
#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

[a,b], đặ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=sTotalsE. Vậy chỉ cần tính
sE
sTotal
!

sTotal=i=abi=i=1bii=1a1i=b(b+1)2(a1)a2

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
a1

Những số chẵn trong đoạn

[a,b] có thể viết lại thành
2i
với
a2ib2

sE=i=a2b22i=2i=a2b2i=2(i=1b2ii=1a21i)=2(b2(b2+1)2(a21)a22)

sE được tính bằng cách lấy tổng các số từ

a2 đến
b2
nhân đôi lên

Sau khi đã tính được

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

VD: Trong đoạn

[3,10] có những số chẵn sau:
4,6,8,10
.
Tương ứng với:
22,23,24,25
.

sTotal=10(10+1)2(31)32=52

a2=102=5
b2=32=2

sE=2(5(5+1)2(21)22)=28

sO=sTotalsE=5228=24

Độ phức tạp thời gian:

O(1).

Code
#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

A1,A2,A3,,An
(n106)
.
Đếm số cách chọn cặp
Ai,Aj
(i<j)
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

Ai, tương ứng với mỗi giá trị lại duyệt tuần tự một lần nữa để tìm
Aj
. 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(Ai+Aj)
có chẵn hay không.

Độ phức tạp thời gian:

O(ba+1).

Code
#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(Ai+Aj) phụ thuộc vào tính chẵn lẻ của
(Ai+Aj)
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
(Ai+Aj)
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ẻ
(Ai+Aj)
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:

  • cnt0
    : số lượng số chẵn.
  • cnt1
    : số lượng số lẻ.

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

  • Số cặp chẵn - chẵn:
    cnt0(cnt01)2
    .
  • Số cặp lẻ - lẻ:
    cnt1(cnt11)2
  • Số cặp chẵn - lẻ:
    cnt0cnt1

Độ phức tạp thời gian:

O(n).

Code
#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

A1,A2,A3,...,An
(n105)
. 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(2n).

AC:

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

Định nghĩa

dpi 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:

  • dp1
    =
    A1
    : Trường hợp cơ sở.
  • dpi=max(dpi1,dpi2+Ai)
    (i2)
    :
    • dpi=dpi1
      : Không lấy
      Ai
      vào tổng tối ưu.
    • dpi=dpi2+Ai
      : Lấy
      Ai
      vào tổng tối ưu.

Kết quả:

dpn.

Độ phức tạp thời gian:

O(n).

Code
#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; }