Transcript
Page 1: Gợi ý PTIT Summer Round 2

Một vài gợi ý PTIT Summer round 2

Bài A: Tìm số. Giả sử n = k1*(k1 + 1)/2 + k2*(k2+1)/2 và 1 <= k1 <= k2.

Nên ta có k1(k1+1) <= 10^9 => k1^2 < 10^9. Ta đã giới hạn được k1.

Duyệt k1, rồi tìm k2 bằng nhiều cách khác nhau như giải hệ, chặt nhị phân v..v

Bài B: Dãy số. Ta sẽ thấy việc tính F(a) chỉ mất khoảng log2(a), và giá trị hàm F cũng chỉ vào khoảng log(a),

đây là một giá trị nhỏ.

Giả sử có k số có giá trị hàm F cùng giá trị vậy sẽ có k*(k-1)/2 cặp cho cùng giá trị.

Tương tự cho các giá trị khác. Kết quả là tổng tất cả các cặp có được của mỗi giá trị.

Bài C: Trò chơi snake. Duyệt BFS. Khó khăn nằm ở việc đánh dấu trạng thái đã duyệt. Ta sẽ lưu lại trạng thái bằng cách

lưu tọa độ của đầu con rắn, và lưu vị trí tương đối giữa các khúc thứ i với khúc thứ i+1của con

rắn. Có 4 hướng, ta đánh số là 0,1,2,3. Như vậy, cần dùng 2 bit để mã hóa cho một vị trí tương

đối giữa 2 khúc liên tiếp. Con rắn có chiều dài tối đa bằng 9, trường hợp này đánh dấu trạng thái

bao gồm tọa độ đầu rắn + dãy 16 bit để mã hóa vị trí tương đối giữa các khúc liên tiếp.

Ví dụ:

4 5

##...

..1#@

432#.

...#.

Đầu con rắn có tọa độ hàng 2, cột 3. Vị trí tương đối giữa các khúc liên tiếp (từ đầu rắn) là

xuống, trái, trái.

Độ phức tạp: con rắn có chiều dài lớn nhất bằng 9, trạng thái cần lưu gồm 8 vị trí tương đối giữa

các khúc liên tiếp, số trạng thái phải duyệt tối đa 15*15*16^2.

Bài D: Câu thần chú của Alidada. Cách thứ nhất: Hashing + chặt nhị phân.

Tìm tập các giá trị độ dài L có S[1..L] = S[S.length – L+1, S.length]. Với Hashing, chi phí kiểm

tra cho mỗi giá trị l là O(1).

Sau đó chặt nhị phân để tìm giá trị L lớn nhất trong tập hợp trên sao cho tồn tại a thỏa mãn

S[1..L] = S[a..a+L-1] với 2 <= a <= S.length – L.

Page 2: Gợi ý PTIT Summer Round 2

Cách thứ hai: sử dụng thuật toán KMP.

Trong thuật toán KMP, hàm next[i] = j sẽ cho ta biết S[1 .. j] = S[i – j+1 .. i].

Bài E: Tập hợp. Một bài toán sinh thông thường. Giới hạn k nhỏ (k <= 10), sinh ra tất cả các bộ số rồi kiểm tra.

Bài F: So sánh DNA. Bài toán dãy con chung dài nhất. Độ phức tạp bằng số test * n^2.

Gọi F[i][j] là độ dài dãy con chung dài nhất của dãy a[1..i] và b[1..j], có kết thúc tại a[i] và b[j].

Thuật toán quy hoạch động như sau:

FOR(i,1,n) FOR(j,1,n){

if(abs(a[i]-b[j]) <= 1) F[i][j] = F[i-1][j-1]+1;

else F[i][j] = 0;

}

Đáp số bằng max F[i][j] với mọi i, j. Trong bài toán này ta cần điều kiện độ dài dãy con chung

lớn hơn hoặc bằng (n+1)/2.

Bài G: Mã hóa. Bài toán không khó. Cần tránh lỗi nhập xâu trong khi đọc dữ liệu.

Bài H: Truy tìm kho báu. Sắp xếp topo.

Sắp xếp topo trong đồ thị là sắp xếp danh sách thứ tự các đỉnh sao cho với mọi cung u v của

đồ thị thì đỉnh u nằm trước đỉnh v trong danh sách sắp xếp.

Với bài toán này, coi mỗi chỉ dẫn là một cung của đồ thị, chúng ta cần tìm ra một thứ tự topo của

danh sách đỉnh. Nếu không có cách sắp xếp nào, có nghĩa là đồ thị có chu trình, trường hợp

“recheck hints”, nếu có nhiều cách sắp xếp thỏa mãn sẽ là trường hợp “missing hints”.

Cách giải quyết: Duyệt DFS hoặc tham lam như sau: lần lượt loại bỏ đi các đỉnh có bậc vào bằng

0. Nếu không loại bỏ hết được n đỉnh, sẽ tồn tại chu trình trong đồ thị. Trong trường hợp ngược

lại, nếu tại thời điểm nào đó mà có nhiều hơn 2 đỉnh có bậc vào bằng 0, trường hợp này sẽ có

nhiều đáp án. Nếu không, in ra danh sách đỉnh theo thứ tự đã xóa.

Bài I: Hàng rào.

Bài J: Cắt bánh. Chặt nhị phân.

Page 3: Gợi ý PTIT Summer Round 2

Với điểm P(0, b) bất kì nằm trên trục Oy, ta luôn tìm được aL sao cho đường thẳng y = aL+b

chia đa giác bên trái thành hai hình bằng nhau. Tìm aL bằng cách sử dụng chặt nhị phân cho đến

khi diện tích 2 phần bị cắt bởi đường thẳng là bằng nhau. Tương tự cho với aR.

Ta cần tìm điểm P sao cho 2 đường thẳng này trùng nhau, tức aL = aR.

Khi b tăng (điểm P dịch lên trên), aL tăng. Với hình bên phải, khi b tăng thì aR giảm. Xét hàm số

a(b) = aL(b) – aR(b) là một hàm số đồng biến theo b. Khi b tiến ra dương vô cùng, aL(b) – aR(b)

> 0, khi b tiến tới âm vô cùng, aL(b) – aR(b) < 0. Do đó, phương trình a(b) = 0 luôn có nghiệm

và là duy nhất. Dựa vào tính chất đồng biến của hàm a(b), ta sẽ chặt nhị phân để tìm b.

Thuật toán như sau:

lowB = -infi, highB = infi, midB;

while(lowB <= highB){

midB = (lowB+highB)/2;

using binary search to find aL and aR;

if(aL == aR) return aL and midB;

else if(aL < aR) lowB = midB;

else if(aL > aR) highB = midB;

}