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

Một vài gợi ý PTIT Summer Round 1

Problem A: Đi đường nào.

Hàm ccw (counter-clockwise) giữa 3 điểm A, B, C. ccw(point A, B, C) cho biết hướng quay của

vector AB tới vector AC.

Hàm ccw được tính bằng tích có hướng của vector AB và AC.

Nếu ccw = 0, có nghĩa là 3 điểm thẳng hàng (góc quay bằng 0).

Nếu ccw > 0, có nghĩa là quay sang trái (ngược chiều kim đồng hồ).

Nếu ccw < 0 có nghĩa quay sang phải (theo chiều kim đồng hồ).

Hàm ccw là một trong những công cụ rất hữu hiệu trong các bài toán hình học, chẳng hạn như

bài toán tìm bao lồi của một tập hợp điểm cho trước.

Problem B: Hoán vị. Cần tìm xem những số nào chưa xuất hiện trong hoán vị thì thay nó bằng phép biến đổi.

Problem C: Các triều đại. Giải thuật quy hoạch động.

Gọi F[i][j] là tên triều đại dài nhất có thể bắt đầu bằng chữ cái “i” và kết thúc bằng chữ cái “j”.

Giờ đây, khi ta có một cái tên S mới, xét cái tên này có thể ghép với triều đại nào đó mà đang có

kết thúc trùng với chữ cái đầu của S. Từ đây ta xây dựng được công thức QHĐ.

Kết quả: max (F[i][i]) với i là các chữ cái từ „a‟ tới „z‟.

Problem D: Đoạn con có K phần tử bằng nhau. Giả sử đoạn con này bắt đầu tại vị trí i và j là vị trí đầu tiên mà dãy a[i…j] thỏa mãn đề bài rõ

ràng các vị trí sau j sẽ thỏa mãn.

Xét đoạn con tiếp theo, là dãy từ a[i+1] tới a[k] với k >= j+1 thỏa mãn. Kế thừa kết quả từ đoạn

con trước, ta chỉ cần duyệt từ vị trí j+1 k. Tư tưởng bài toán này là duyệt theo khung cửa sổ.

Để kiểm tra xem đoạn có K phần tử bằng nhau không, ta sẽ đếm số lượng của một giá trị trong

đoạn, có thể dùng map hoặc rời rạc hóa dữ liệu để thực hiện.

Bài E: Điện tâm đồ. Chú ý, để hiện thị kí tự \ ta phải viết là „\\‟. Hoặc có thể in ra kí tự „\‟ dựa vào mã ASCII của nó.

Page 2: Gợi ý PTIT Summer Round 1

Bài F: Ném đá. Bài toán không khó. Chỉ cần viết một hàm đệ quy mô tả các bước đi của viên đá từ trên xuống

dưới như mô tả của đề bài.

Bài G: Trò chơi với những con số. Trường hợp 1: Nếu X >= 10^6, sẽ có tối đa B/X (max = 10^5) số là bội của X. Vì vậy, sử dụng

một vòng FOR từ A tới B để tìm tất cả các số chia hết cho X, sau đó kiểm tra thêm điều kiện các

chữ số phải thỏa mãn xuất hiện trong tập hợp yêu cầu.

Trường hợp 2: X < 10^6, quy hoạch động có nhớ.

Gọi dp(n, prefix) là số bội của X nằm trong đoạn [A, B] với tiền tố là prefix và cần phải thêm

vào n chữ số. Với mỗi cặp n, prefix, ta cần xét các số nằm trong đoạn [prefix * 10^n (cận dưới),

prefix*10^(n+1)-1 (cận trên)].

Công thức QHĐ:

FOR(i,0,9) if(isNum[i]) dp(n, prefix) += dp(n-1, prefix*10+i).

Trong đó isNum[i] trả về true nếu i là một trong những chữ số của tập hợp đã cho.

Nếu A <= cận dưới và cận trên <= B (đoạn đang xét là đoạn con của đoạn [A, B]), khi đó các giá

trị prefix có phần dư giống nhau với X sẽ có cùng số lượng bội của X, nên ta sẽ sử dụng đánh

dấu ở phần này để tăng tốc độ tính toán.

Bài H: Hình chữ nhật 3D. Giới hạn nhỏ, n <= 1000 nên hoàn toàn có thể xử lí bằng 2 vòng FOR để kiểm tra từng cặp hình

chữ nhật có giao nhau hay không? Trong mặt phẳng 2 chiều, điều kiện để 2 hình chữ nhật có tọa

độ cặp đỉnh trái dưới, phải trên A(xA, yA), B(xB, yB) và C(xC, yC), D(xD, yD) không giao nhau

là:

min(xA, xB) > max(xC, xD) || max(xA, xB) < min(xC, xD) || min(yA, yB) > max(yC, yD) ||

max(yA, yB) < min (yC, yD).

Với hình chữ nhật trong không gian 3 chiều, thêm điều kiện về tọa độ trên trục z tương tự như

trên là đủ.

Với giới hạn lớn hơn, cần sử dụng BIT 2D và kĩ thuật sweep line . Gọi các hình chữ nhật có

chung tọa độ trên trục Ox là nhóm X, tương tự với nhóm Y, Z. Đếm số lượng hình chữ nhật giao

nhau trên từng cặp X-X, Y-Y, Z-Z (loại 1) và X-Y, Y-Z, Z-X (loại 2).

Đối với loại 1, giả sử xét cặp X-X (mặt phẳng x = x1), ta cần đếm có bao nhiêu cặp hình chữ

nhật giao nhau trên mặt phẳng x = x1?

Page 3: Gợi ý PTIT Summer Round 1

Với loại 2, giả sử xét cặp X-Y(mặt phẳng x = x1 và y = y1), chiếu hcn loại Y lên mặt phẳng x =

x1, sẽ chỉ còn là một đoạn thẳng. Xét tất cả các hình chữ nhật nằm trên mặt phẳng x = x1, ta cần

tìm xem có bao nhiêu hcn giao nhau với đoạn thẳng kia?

Bài I: Đếm số miền. Hình học + đồ thị phẳng.

Định lý Euler trong đồ thị phẳng: n-m+r = 2, trong đó n là số đỉnh, m là số cạnh và r là số miền

tạo bởi đồ thị phẳng này.

Với n hình chữ nhật đã cho, tìm tất cả các giao điểm. Sau đó dựng nên đồ thị mới từ tất cả các

điểm có trên mặt phẳng. Duyệt DFS để tìm các thành phần liên thông, với mỗi thành phần liên

thông, áp dụng công thức Euler để tìm ra số miền.

Bài J: Dãy tăng dài nhất. 3 bài toán sau kế thừa nhau.

Bài toán trên không gian 1 chiều: Dãy con tăng dài nhất (LIS).

Gọi dp[i] là độ dài dãy con tăng dài nhất kết thúc tại phần tử a[i].

Gọi L[i] là tập hợp tất cả các phần tử x có dp[x] = i. Thực ra ta chỉ cần quan tâm tới giá trị nhỏ

nhất trong tập hợp L[i].

Duyệt từ đầu tới cuối, tại phần tử thứ i, ta cần chặt nhị phân, tìm độ dài leng lớn nhất sao cho tập

hợp L[leng] != rỗng, sau đó push a[i] vào tập hợp L[leng+1].

Độ dài của dãy con tăng dài nhất bằng chỉ số i lớn nhất sao cho L[i] có ít nhất 1 phần tử.

Không gian 2 chiều: tìm một tập hợp sao cho có thể tạo thành dãy tăng dài nhất:

http://vn.spoj.com/problems/MCONVOI/

Đầu tiên cần sort các điểm theo thứ tự x tăng dần.

Gọi dp[i] là độ dài dãy tăng dài nhất kết thúc tại điểm a[i], L[i] là tập hợp tất cả các điểm x có

dp[x] = i.

Với bài toán trong không gian 1D, coi mỗi điểm gồm 2 thành phần, thì với mỗi hoành độ x chỉ

có một tung độ y duy nhất. Điều khác biệt là trong không gian 2D, có thể có nhiều điểm có

chung hoành độ x.

Trong tập hợp L[i], ta cũng chỉ cần quan tâm tới phần tử nhỏ nhất, vì thành phần x đã được sắp

xếp theo thứ tự tăng dần nên chỉ cần quan tâm tới điểm có thành phần y nhỏ nhất trong tập hợp

L[i].

Page 4: Gợi ý PTIT Summer Round 1

Một trong những cách xử lí khá hiệu quả là sort các điểm có chung thành phần x theo thứ tự

giảm dần của thành phần y. Khi đó sẽ không phải xử lí trường hợp trùng thành phần x do thao

tác push a[i] vào tập hợp L[leng+1].

Không gian 3 chiều:

Để tránh trường hợp xử lí trùng, trước hết cũng sort các điểm theo ưu tiên x tăng dần, y giảm

dần, z giảm dần.

Tại điểm a[i], cần tìm L[leng] với leng lớn nhất sao cho L[leng] có một phần tử P nào đó thỏa

mãn P.x < a[i].x && P.y < a[i].y && P.z < a[i].z .

Chỉ quan tâm tới thành phần y và z, ta sẽ thấy L[leng] không tồn tại 2 điểm P, Q nào sao cho P <

Q. (Thật vậy, nếu tồn tại điểm P và Q theo thứ tự sao cho P.y < Q.y và P.z < Q.z, do P xuất hiện

trước Q nên P.x < Q.x. Do đó, điểm Q sẽ phải nằm trong tập hợp L[leng+1] chứ không phải tập

hợp L[leng]).

Để giải quyết được bài toán, ta cần tăng tốc độ cho thao tác kiểm tra và push điểm a[i], như vậy

cần phải duy trì tập hợp L[leng] theo thứ tự. Vì chỉ cần quan tâm tới các điểm có thành phần y, z

nhỏ nhất, mỗi tọa độ y chỉ lưu lại một điểm duy nhất.

Thao tác update khi push điểm a[i] vào tập hợp L[leng]: cần xóa bỏ các điểm Q >= a[i].