Phần 1. Đề thi
Câu 1. (6 điểm) Vị trí tốt
Cho dãy A gồm N phần tử là các số nguyên a1, a2, … aN. Vị trí i được gọi là một vị trí tốt nếu như ai bằng tổng tất cả các số xuất hiện ở vị trí trước i (1 ≤ i ≤ N)
Yêu cầu: Hãy tìm các vị trí tốt trong dãy A
Dữ liệu: Vào từ tệp GPOS.INP gồm:
– Dòng 1: Chứa số nguyên dương N (N ≤ 2*10^5)
– Dòng 2: Chứa N số nguyên a1, a2,… aN (|ai| ≤ 10^9)
Kết quả: Ghi ra tệp GPOS.OUT gồm:
– Nếu tìm được các vị trí tốt:
+ Dòng 1: Ghi số lượng các vị trí tốt tìm được.
+ Dòng 2: Ghi ra các vị trí tốt tìm được theo giá trị tăng dần, các số cách nhau một dấu cách.
– Nếu không có vị trí tốt nào thì chỉ in ra -1
Ví dụ:
GPOS.INP | GPOS.OUT |
10 1 2 4 7 -9 -2 3 6 1 4 | 3 4 7 8 |
10 1 2 6 7 2 8 -10 1 -9 5 | -1 |
Ràng buộc:
– Có 80% số test ứng với N ≤ 1000, |ai| ≤ 10^5
– Có 20% số test ứng với N ≤ 2*10^5, |ai| ≤ 10^9
Câu 2. (6 điểm) Mật mã Lazi
Để giải được mật mã Lazi, người giải mã cần có khóa. Khóa là ước nguyên tố có giá trị lớn nhất trong các ước nguyên tố của các số có trong chuỗi ký tự.
Cho xâu ký tự S có độ dài tối đa 255 ký tự, gồm các ký tự chữ cái và ký tự số. Các ký tự số liền nhau sẽ tạo thành một số duy nhất.
Yêu cầu: Hãy tìm khóa trong xâu S để giải mật mã Lazi. Các số trong xâu có giá trị nhỏ hơn 10^12. Dữ liệu vào đảm bảo có khóa.
Dữ liệu: Vào từ tệp BLAZI.INP có duy nhất một xâu S.
Kết quả: Ghi ra tệp BLAZI.OUT khóa tìm được.
Ví dụ:
BLAZI.INP | BLAZI.OUT |
42abc11deab34 | 17 |
10 1 2 6 7 2 8 -10 1 -9 5 | -1 |
Giải thích: Số 42 có ước nguyên tố lớn nhất là 7; Số 11 có ước nguyên tố lớn nhất là 11; Số 34 có ước nguyên tố lớn nhất la 17. Khóa giải mật mã Lazi là 17.
Ràng buộc:
– Có 80% số test ứng với các số xâu nhỏ hơn 10^5
– Có 20% số test ứng với các số xâu nhỏ hơn 10^9
Câu 3. (5 điểm) Mua bán nhà
Công ty bất động sản Will Hill mở bán N căn nhà, căn nhà thứ i có giá là ai triệu đồng (1 ≤ i ≤ N). Có M khách hàng, khách hàng thứ j đăng ký mua nhà với giá bj triệu đồng (1 ≤ j ≤ N). Các khách hàng đều chấp nhận mua nhà với độ chênh lệch giá so với mong muốn không quá k triệu đồng. Nếu khách hàng đăng ký mua nhà với giá bj, thì họ có thể chấp nhận mua căn nhà có giá từ bj – k đến bj + k (0 ≤ k ≤ 10^9)
Yêu cầu: Hãy cho biết số lượng nhiều nhất các căn nhà mà công ty có thể bán.
Dữ liệu: Vào từ tệp HOUSE.INP gồm:
– Dòng 1: Chứa ba số nguyên không âm N, M và k tương ứng là số lượng căn nhà, số lượng khách hàng và độ chênh lệch giá so với mong muốn.
– Dòng 2: Ghi các số a1, a2, … aN (1 ≤ ai ≤ 10^9) tương ứng là giá của N căn nhà
– Dòng 3: Ghi các số b1, b2,… bM (1 ≤ aj ≤ 10^9) tương ứng là giá đăng ký mua nhà của M khách hàng.
Các số trên một dòng được ghi cách nhau bởi dấu cách.
Kết quả: Ghi ra tệp HOUSE.OUT số lượng nhiều nhất các căn nhà mà công ty có thể bán.
Ví dụ:
HOUSE.INP | HOUSE.OUT |
3 5 200 1200 800 3800 1800 1100 3000 2500 4000 | 2 |
Giải thích: Căn nhà 1 bán cho khách hàng 2; căn nhà 3 bán cho khách hàng 5
Ràng buộc:
Có 40% test ứng với 1 < N, M ≤ 1000; k = 0;
Có 30% test ứng với 1 < N, M ≤ 1000; 0 ≤ k ≤ 10^9;
Có 30% test ứng với 1 < N, M ≤ 2*10^5; 0 ≤ k ≤ 10^9.
Câu 4. (3 điểm) Chọn quà
Cho N sản phẩm, sản phẩm thứ i có khối lượng Mi và các giá trị Pi (1 ≤ i ≤ N). Bạn được chọn một số sản phẩm khác nhau sao cho tổng khối lượng các sản phẩm được chọn đúng bằng K và tổng giá trị các sản phẩm là lớn nhất.
Dữ liệu: Vào từ tệp DQCN.INP gồm:
- Dòng 1: Ghi số nguyên dương N và K (N ≤ 100, K ≤ 10^3)
- N dòng tiếp theo, mỗi dòng ghi 2 số nguyên dương Mi và Pi (Mi, Pi ≤ 10^3).
Các số trên một dòng ghi cách nhau bởi một dấu cách.
Kết quả: Ghi ra tệp DQCN.OUT tổng giá trị lớn nhất chọn được. Nếu không có cách chọn sản phẩm thỏa mãn thì ghi ra NONE.
Ví dụ:
DQCN.INP | DQCN.OUT |
4 25 10 13 15 23 10 2 4 40 | 36 |
4 11 10 13 15 23 10 2 4 40 | NONE |
Giải thích: Chọn sản phẩm 1 và sản phẩm 2 có tổng khối lượng 25, tổng giá trị là 36
Ràng buộc:
Có 50% số test ứng với N ≤ 20
Có 50% số test ứng với N ≤ 100
Phần 2. Code tham khảo (C++)
Câu 1. (6 điểm) Vị trí tốt
#include <iostream>
#include <vector>
using namespace std;
// Hàm để tìm các vị trí tốt trong một dãy số
vector<int> find_good_positions(vector<int> &a) {
// Khởi tạo một biến để lưu tổng các số trước vị trí hiện tại
int prefix_sum = 0;
// Khởi tạo một vector để lưu các vị trí tốt
vector<int> good_positions;
// Lặp qua các phần tử của dãy số
for (int i = 0; i < a.size(); ++i) {
// Nếu phần tử hiện tại bằng tổng các số trước đó
if (a[i] == prefix_sum) {
// Thêm vị trí hiện tại vào vector
good_positions.push_back(i + 1); // Cộng 1 vì vị trí bắt đầu từ 1
}
// Cập nhật tổng các số trước vị trí hiện tại
prefix_sum += a[i];
}
// Trả về vector các vị trí tốt
return good_positions;
}
int main() {
freopen("GPOS.INP", "r", stdin);
freopen("GPOS.OUT", "w", stdout);
int N;
cin >> N;
vector<int> A(N);
for (int i = 0; i < N; ++i) {
cin >> A[i];
}
// Tìm các vị trí tốt
vector<int> good_positions = find_good_positions(A);
if (good_positions.size() > 0) {
cout << good_positions.size() << endl;
for (int i = 0; i < good_positions.size(); ++i) {
cout << good_positions[i] << " ";
}
cout << endl;
} else {
cout << "-1" << endl;
}
return 0;
}
Câu 2. (6 điểm) Mật mã Lazi
#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
using namespace std;
// Hàm để tìm ước nguyên tố lớn nhất của một số
long long largest_prime_factor(long long n) {
long long max_factor = 1;
for (long long i = 2; i <= sqrt(n); ++i) {
if (n % i == 0) {
max_factor = i;
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1 && n > max_factor) {
max_factor = n;
}
return max_factor;
}
// Hàm để tìm khóa để giải mật mã Lazi trong một xâu ký tự
long long find_key(string s) {
long long key = 0;
long long num = 0;
for (char c : s) {
if (isdigit(c)) {
num = num * 10 + (c - '0');
} else {
if (num != 0) {
long long factor = largest_prime_factor(num);
if (factor > key) {
key = factor;
}
num = 0;
}
}
}
if (num != 0) {
long long factor = largest_prime_factor(num);
if (factor > key) {
key = factor;
}
}
return key;
}
int main() {
freopen("BLAZI.INP", "r", stdin);
freopen("BLAZI.OUT", "w", stdout);
string S;
getline(cin, S);
// Tìm khóa
long long key = find_key(S);
// Ghi kết quả vào file output
cout << key << endl;
return 0;
}
Câu 3. (5 điểm) Mua bán nhà
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
// Hàm để tìm số lượng nhiều nhất các căn nhà mà công ty có thể bán
int max_houses(int N, int M, int k, vector<int>& a, vector<int>& b) {
// Sắp xếp các giá của căn nhà và khách hàng theo thứ tự tăng dần
sort(a.begin(), a.end());
sort(b.begin(), b.end());
// Khởi tạo biến để lưu số lượng căn nhà đã bán
int count = 0;
// Khởi tạo biến để lưu chỉ số của khách hàng hiện tại
int j = 0;
// Lặp qua các giá của căn nhà
for (int i = 0; i < N; ++i) {
// Nếu chỉ số của khách hàng vượt quá số lượng khách hàng
if (j >= M) {
// Dừng vòng lặp
break;
}
// Nếu giá của căn nhà nằm trong khoảng chấp nhận của khách hàng
if (b[j] - k <= a[i] && a[i] <= b[j] + k) {
// Tăng số lượng căn nhà đã bán lên 1
count++;
// Tăng chỉ số của khách hàng lên 1
j++;
}
// Nếu giá của căn nhà lớn hơn khoảng chấp nhận của khách hàng
else if (a[i] > b[j] + k) {
// Tăng chỉ số của khách hàng lên 1, tăng số lượng căn nhà đã bán lên 1
j++;
count++;
}
}
// Trả về số lượng căn nhà đã bán
return count;
}
int main() {
freopen("HOUSE.INP", "r", stdin);
freopen("HOUSE.OUT", "w", stdout);
int N, M, k;
cin >> N >> M >> k;
vector<int> a(N), b(M);
for (int i = 0; i < N; ++i) {
cin >> a[i];
}
for (int i = 0; i < M; ++i) {
cin >> b[i];
}
// Tìm số lượng nhiều nhất các căn nhà mà công ty có thể bán
int result = max_houses(N, M, k, a, b);
// Ghi kết quả vào file output
cout << result << endl;
return 0;
}
Câu 4. (3 điểm) Chọn quà
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
// Hàm để giải bài toán chọn quà
int solve(int N, int K, vector<int>& M, vector<int>& P) {
// Khởi tạo mảng F[j] là tổng giá trị lớn nhất khi chọn các sản phẩm khác nhau sao cho tổng khối lượng bằng j
vector<int> F(K + 1, 0);
// Gán F[0] bằng 1
F[0] = 1;
// Duyệt qua các sản phẩm
for (int i = 0; i < N; ++i) {
// Duyệt ngược qua các khối lượng từ K đến M[i]
for (int j = K; j >= M[i]; --j) {
// Nếu F[j - M[i]] khác 0
if (F[j - M[i]] != 0) {
// Cập nhật F[j] bằng max của F[j] và F[j - M[i]] + P[i]
F[j] = max(F[j], F[j - M[i]] + P[i]);
}
}
}
// Trả về kết quả là F[K]
return F[K];
}
int main() {
// Mở file input để đọc dữ liệu
freopen("DQCN.INP", "r", stdin);
// Mở file output để ghi kết quả
freopen("DQCN.OUT", "w", stdout);
int N, K;
// Đọc số lượng sản phẩm và tổng khối lượng cần đạt được
cin >> N >> K;
vector<int> M(N), P(N);
// Đọc khối lượng và giá trị của từng sản phẩm
for (int i = 0; i < N; ++i) {
cin >> M[i] >> P[i];
}
// Tìm giá trị lớn nhất có thể đạt được
int result = solve(N, K, M, P);
// Ghi kết quả vào file output
if (result == 0) {
cout << "NONE" << endl;
} else {
cout << result - 1 << endl;
}
return 0;
}
Phần 3. Code tham khảo (Python)
Câu 1. (6 điểm) Vị trí tốt
# Hàm để tìm các vị trí tốt trong một dãy số
def find_good_positions(a):
# Khởi tạo một biến để lưu tổng các số trước vị trí hiện tại
prefix_sum = 0
# Khởi tạo một danh sách để lưu các vị trí tốt
good_positions = []
# Lặp qua các phần tử của dãy số
for i in range(len(a)):
# Nếu phần tử hiện tại bằng tổng các số trước đó
if a[i] == prefix_sum:
# Thêm vị trí hiện tại vào danh sách
good_positions.append(i + 1) # Cộng 1 vì vị trí bắt đầu từ 1
# Cập nhật tổng các số trước vị trí hiện tại
prefix_sum += a[i]
# Trả về danh sách các vị trí tốt
return good_positions
# Đọc dữ liệu từ file input
with open('GPOS.INP', 'r') as file:
N = int(file.readline())
A = list(map(int, file.readline().split()))
# Tìm các vị trí tốt
good_positions = find_good_positions(A)
# Ghi kết quả vào file output
with open('GPOS.OUT', 'w') as file:
if len(good_positions) > 0:
file.write(str(len(good_positions)) + '\n')
file.write(' '.join(map(str, good_positions)) + '\n')
else:
file.write('-1\n')
Câu 2. (6 điểm) Mật mã Lazi
# Hàm để tìm ước nguyên tố lớn nhất của một số
def largest_prime_factor(n):
# Khởi tạo một biến để lưu ước nguyên tố lớn nhất
max_factor = 1
# Lặp qua các số từ 2 đến căn bậc hai của n
for i in range(2, int(n**0.5) + 1):
# Nếu n chia hết cho i
if n % i == 0:
# Cập nhật ước nguyên tố lớn nhất
max_factor = i
# Chia n cho i cho đến khi không chia hết
while n % i == 0:
n //= i
# Nếu n lớn hơn 1 và lớn hơn ước nguyên tố lớn nhất
if n > 1 and n > max_factor:
# Cập nhật ước nguyên tố lớn nhất
max_factor = n
# Trả về ước nguyên tố lớn nhất
return max_factor
# Hàm để tìm khóa để giải mật mã Lazi trong một xâu ký tự
def find_key(s):
# Khởi tạo một biến để lưu khóa
key = 0
# Khởi tạo một biến để lưu số hiện tại
num = 0
# Lặp qua các ký tự của xâu
for c in s:
# Nếu ký tự là số
if c.isdigit():
# Cập nhật số hiện tại bằng cách nhân 10 và cộng ký tự
num = num * 10 + int(c)
# Nếu ký tự không phải là số
else:
# Nếu số hiện tại khác 0
if num != 0:
# Tìm ước nguyên tố lớn nhất của số hiện tại
factor = largest_prime_factor(num)
# Nếu ước nguyên tố lớn hơn khóa
if factor > key:
# Cập nhật khóa
key = factor
# Đặt lại số hiện tại bằng 0
num = 0
# Nếu số hiện tại khác 0
if num != 0:
# Tìm ước nguyên tố lớn nhất của số hiện tại
factor = largest_prime_factor(num)
# Nếu ước nguyên tố lớn hơn khóa
if factor > key:
# Cập nhật khóa
key = factor
# Trả về khóa
return key
# Đọc dữ liệu từ file input
with open('BLAZI.INP', 'r') as file:
S = file.readline().strip()
# Tìm khóa
key = find_key(S)
# Ghi kết quả vào file output
with open('BLAZI.OUT', 'w') as file:
file.write(str(key))
Câu 3. (5 điểm) Mua bán nhà
# Hàm để tìm số lượng nhiều nhất các căn nhà mà công ty có thể bán
def max_houses(N, M, k, a, b):
# Sắp xếp các giá của căn nhà và khách hàng theo thứ tự tăng dần
a.sort()
b.sort()
# Khởi tạo biến để lưu số lượng căn nhà đã bán
count = 0
# Khởi tạo biến để lưu chỉ số của khách hàng hiện tại
j = 0
# Lặp qua các giá của căn nhà
for i in range(N):
# Nếu chỉ số của khách hàng vượt quá số lượng khách hàng
if j >= M:
# Dừng vòng lặp
break
# Nếu giá của căn nhà nằm trong khoảng chấp nhận của khách hàng
if b[j] - k <= a[i] <= b[j] + k:
# Tăng số lượng căn nhà đã bán lên 1
count += 1
# Tăng chỉ số của khách hàng lên 1
j += 1
# Nếu giá của căn nhà nhỏ hơn khoảng chấp nhận của khách hàng
elif a[i] < b[j] - k:
# Bỏ qua căn nhà này
continue
# Nếu giá của căn nhà lớn hơn khoảng chấp nhận của khách hàng
else:
# Tăng chỉ số của khách hàng lên 1, tăng số lượng căn nhà đã bán lên 1
j += 1
count += 1
# Trả về số lượng căn nhà đã bán
return count
# Đọc dữ liệu từ file input
with open('HOUSE.INP', 'r') as file:
N, M, k = map(int, file.readline().split())
a = list(map(int, file.readline().split()))
b = list(map(int, file.readline().split()))
# Tìm số lượng nhiều nhất các căn nhà mà công ty có thể bán
result = max_houses(N, M, k, a, b)
# Ghi kết quả vào file output
with open('HOUSE.OUT', 'w') as file:
file.write(str(result))
Câu 4. (3 điểm) Chọn quà
# Hàm để giải bài toán chọn quà
def solve(N, K, M, P):
# Khởi tạo mảng F[j] là tổng giá trị lớn nhất khi chọn các sản phẩm khác nhau sao cho tổng khối lượng bằng j
F = [0 for j in range(K + 1)]
# Gán F[0] bằng 1
F[0] = 1
# Duyệt qua các sản phẩm
for i in range(N):
# Duyệt ngược qua các khối lượng từ K đến M[i]
for j in range(K, M[i] - 1, -1):
# Kiểm tra xem F[j - M[i]] có bằng 0 hay không
if F[j - M[i]] != 0:
# Nếu không bằng 0, thì cập nhật F[j] bằng max của F[j] và F[j - M[i]] + P[i]
F[j] = max(F[j], F[j - M[i]] + P[i])
# Trả về kết quả là F[K]
return F[K]
# Đọc dữ liệu từ file input
with open('DQCN.INP', 'r') as file:
N, K = map(int, file.readline().split())
M, P = zip(*[map(int, line.split()) for line in file])
# Tìm tổng giá trị lớn nhất của các sản phẩm được chọn sao cho tổng khối lượng bằng K
result = solve(N, K, M, P)
# Ghi kết quả vào file output
with open('DQCN.OUT', 'w') as file:
if result == 0:
file.write("NONE\n")
else:
file.write(str(result-1) + "\n")