Skip to content

DTQG #5 Editorial

22 Nov 2023

Bài 1

Vì ta chỉ xét một đoạn liên tiếp, nên ta biết được rằng, các kí tự ngoặc đóng sẽ luôn match kí tự ngoặc mở gần nhất bên trái giống y như việc match khi xét cả xâu SS. (nếu bài là subsequence sẽ không match được như vậy).

Với mỗi vị trí ii, ta sẽ tìm vị trí jj sao cho [j,i][j, i] match được một dãy ngoặc đúng. Khi đó ta sẽ coi dãy ngoặc này là một dãy ngoặc độc lập (không có dãy nào bao nó). Gọi f[i]f[i] là đáp án khi xét dãy kết thúc tại ii. Khi đó ta có lựa chọn là:

  • Lấy dãy [j,i][j, i] hiện tại nối vào f[j1]f[j - 1].
  • Chỉ lấy dãy [j,i][j, i].
  • Lấy dãy empty.

Bài 2

Gọi dp(j,i)dp(j, i) là số dãy có hai phần tử cuối là jjii. Với mọi kk sao cho kji0k \oplus j \oplus i \neq 0, ta cập nhật dp(i,j)=dp(i,j)+dp(k,j)dp(i, j) = dp(i, j) + dp(k, j).

Làm như trên sẽ mất độ phức tạp là O(n3)O(n^3). Để cải tiến lên O(n2)O(n^2) thì ta thấy chỉ có duy nhất một k=ijk = i \oplus j không thoả mãn. Do đó ta có thể cộng tổng hết dp(k,j)dp(k, j) và trừ đi dp(ij,j)dp(i \oplus j, j).

Giờ ta sẽ giảm xuống chỉ còn một chiều: dp(i)dp(i) là số dãy có kết thúc là ii. Với mọi j<ij < i, ta thực hiện thao tác dp(i)=dp(i)+dp(j)dp(ij)dp(i) = dp(i) + dp(j) - dp(i \oplus j) nếu ij<ji \oplus j < j. Cách làm trên vẫn có độ phức tạp là O(n2)O(n^2) nhưng ta lại có thể cải tiến được.

Thật vậy, ta lưu thêm mảng tổng tiền tố prefDP(i)prefDP(i) là tổng các dpdp từ 00 đến ii. Lúc này dp(i)=prefDP(i1)dp(i) = prefDP(i - 1). Việc cần làm bây giờ là nhóm hết những dp(ij)dp(i \oplus j) thoả mãn j<i,ij<jj < i, i \oplus j < j vào để trừ cho nhanh.

Gọi bit cao nhất của iikk. Ta thấy bit cao nhất của jj tối đa là kk. Nếu bit thứ kk của jj00, thì ij>ji \oplus j > j. Nếu bit thứ kk của jj11 thì ij<ji \oplus j < j (thoả mãn). Vậy ta sẽ chỉ trừ với những jj có bit cao nhất bằng bit cao nhất của ii. Dù đã giảm được cơ số jj phải xét nhưng ta vẫn không thể lưu hoặc xét được mọi iji \oplus j được vì ii thay đổi cũng như có quá nhiều jj.

Giờ ta sẽ làm ngược một chút. Đặt h=ijh = i \oplus j.

  • Điều kiện đầu tiên là bit cao nhất của hh phải khác bit cao nhất của iijj (vì bit cao nhất của ii bằng bit cao nhất của jj => bit tại vị trí đó của iji \oplus j00, khác iijj).
  • Điều kiện tiếp theo là hi<ih \oplus i < i.

Ta sẽ trừ hết tất cả các dp(h)dp(h) thoả mãn như trên (tính đúng đắn được đảm bảo).

Làm ngược như vậy có tác dụng gì? Lúc này khi duyệt ii tăng dần, khi nào bit cao nhất của ii tăng lên một vị trí, ta mới đi cập nhật các dp(h)dp(h) trước đó. Ngoài ra điều kiện hi<ih \oplus i < i sẽ dễ kiểm soát với ii là tham số hơn. Có thể dùng trie để trừ đi các dpdp như trên.

Bài 3

Có thể tóm gọn đề bài là tính diện tích lớn nhất của 11 tplt. Pha tính phần diện tích hợp thì dễ, xử lí như bài Area. Giờ ta chỉ quan tâm pha DSU để hợp nhất các hcn thuộc một tplt.

Ta sẽ sweepline theo xx và merge những thằng có yy giao nhau. Lưu lại các đoạn theo yy trong vector trên các node của segtree. Khi merge thì ta chỉ việc lấy ra. Tuy nhiên nếu không có theo trick thì độ phức tạp sẽ rất lớn. Ta để ý là sau khi merge, chỉ cần lưu đúng 1 phần tử là đại diện được cho tplt. Ta sẽ lưu phần tử bị xoá cuối cùng khi sweepline. Lúc đó ta se có cơ hội merge càng nhiều.

Tuy sol ngắn nhưng code khá ảy chỉa. Các em tự code nhé 😉