NGÀY THỨ NHẤT
Bài 1 : BCHESS
Ý tưởng bài này bắt nguồn từ bài QBSQUARE
Ta cần tính hình vuông lớn nhất giống bàn cờ (0 1 xen kẽ) và số lượng hình vuông như vậy với tính chất
- độ dài chẵn
- độ dài lẻ, góc phải dưới là 0
- độ dài lẻ, góc phải dưới là 1
Gọi F[i,j] và G[i,j] là độ dài hình vuông lớn nhất có góc phải dưới ở ô [i,j] lần lượt với A[i,j]=0 và A[i,j]=1.
Nếu A[i,j] = 0 thì
- G[i,j]=0
- F[i,j]=min(F[i-1,j-1],G[i-1,j],G[i,j-1])+1
Tính tương tự với A[i,j]=1.
Duyệt hết bảng, mỗi lần tính được F[i,j], G[i,j] ta cập nhật vào kết quả. Lưu ý cần cập nhật cho cả độ dài chẵn và độ dài lẻ.
Độ phức tập : O(M*N). Có thể chỉ dùng 1 mảng F[i,j] là độ dài hình vuông lớn nhất có góc phải dưới ở ô [i,j] nhưng phần xét sẽ phức tạp hơn 1 chút.
Bài 2 : DGOLD
Đây là một bài liên quan đến bitmask và chia thành 2 tập con.
Solution 1 : Xem mỗi bit biểu hiện một cách chọn (bit k = 1 nghĩa là có chọn thỏi vàng k+1). F[i] = tổng khối lượng vàng nếu chọn theo dãy bit i.
Duyệt 2^N dãy bit. Với dãy i duyệt các dãy con j của i (i or j = i) Nếu F[i] = F[j] * 2 thì cập nhật F[j] vào kết quả.
Cách duyệt nhanh các dãy bit con của dãy bit S (kể cả S và 0 )
A = S;
while (A>0)
begin
A = S and A; -> lúc này A là dãy bit con của S, dùng A để tính toán
A = A – 1;
end;
Độ phức tập : thoạt nhiên tưởng lả (2^N)^2 = 4^N nhưng trên thực tế chỉ là 3^N (có thể chứng minh bằng toán hoặc viết chương trình vét trâu) => ăn được trên 50% số điểm.
Solution 2 : Giả sử với N=24
Chia 12 thỏi vàng đầu vào tập 1 và 12 thỏi cuối vào tập 2. Ta cần chọn A và C gam trong tập 1, B và D gam trong tập 2 sao cho :
A + B = C +D <=> A – C = D – B = K => A + B = C + D = A + D – K;
Với tập 1, ta xét tất cả các cách chọn A và C biểu diễn bằng dãy H trong cơ số 3.
- H[i]=1 : chọn thỏi i vào A
- H[i]=2 : chọn thỏi i vào C
- H[i]=0 : không chọn
Có tất cả 3^12 cấu hình -> lưu 3^12 phần tử vào 1 mảng F[i] gồm 2 giá trị x và y
F[i].x = abs (A[i]-C[i])
F[i].y = max ( A[i],C[i] )
Nếu F[i].x = F[j].x ta chỉ cần lưu lại F[i] nếu F[i].y > F[j].y
Tương tự ta tạo mảng G từ 12 thỏi cuối cùng.
Sort lại F và G theo chiều tăng dần của x. Giờ ta duyệt kiếm tất cả các cặp i, j mà F[i].x = G[j].x
Mỗi lần tìm được 1 cặp i,j ta cập nhật ( F[i].y + G[j].y – F[i].x ) cho kết quả.
Độ phức tạp : (3^12) * log (3^12) => ăn 100% số điểm.
Nhận xét : bài này để ăn 100% thì khá khoai nhưng trên 50% thì hoàn toàn dễ dàng

.
Bài 3 : NSRAIL
Nhận xét 1 : ta có thể bỏ đi chiều từ Nam-Bắc bằng cách đặt A[i,j] = A[i,j] + A[j,i] với i>j.
Thay vì kiếm số khách được ăn nhiều nhất ta có thể tiếp cận bài toán dễ dàng hơn nếu tính số khách không được ăn ít nhất.
Gọi dãy X = (x0, x1, x2, ... , xm, xm+1) là 1 cách chọn cách đặt trạm ăn. Mặc định có 1 trạm ăn đặt trước ga 1 (x0=0) và 1 trạm đặt sau ga N (xm+1 = n).
Nhận xét 2 : Chỉ có các khách lên tàu ở ga y1 > xi và ở ga y2 <= xi+1 mới không có phiếu ăn. Ta tính mảng B[i,j] = tổng các A[y1, y2] với i <= y1 <= y2 <= j. Mảng B có thể tính bằng QHĐ nhanh chóng trong O(N^3) : B[i,j] = B[i,j-1] + A[k,j] với (i <= k < j). Có thể cải tiến thành O(N^2) bằng cách tính trước A[k,j] trong O(N^2)
Tìm dãy X sao cho tổng các B[xi+1, xi+1] nhỏ nhất. Gọi mản F[i,j] = kết quả tối ưu khi đã chọn xong j trạm ăn trong i ga đầu tiên. Công thức QHĐ :
F[i,j] = min (F[k,j-1] + B[k+1,j]) với (1 <= k < i)