trang chủ / bài tập / standingout / lời giải

Nổi Bật Trong Đàn

Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Tác giả: huunguyenhuunguyen

Lời giải: Nổi Bật Trong Đàn

Nhận xét quan trọng

Bài toán yêu cầu với mỗi chuỗi si, tính tổng độ dài của tất cả xâu con phân biệt của si mà không xuất hiện trong bất kỳ sj nào khác (ji).

Số lượng xâu con có thể rất lớn, nên ta cần cấu trúc dữ liệu mạnh để xử lý hiệu quả.

Hướng tiếp cận: Suffix Array

Ý tưởng cốt lõi là nối tất cả N chuỗi lại với nhau bằng các ký tự phân cách (ví dụ ?, |, ...) để tạo thành một chuỗi tổng hợp S. Sau đó xây dựng suffix array (mảng hậu tố) và mảng LCP (Longest Common Prefix) cho S.

Tại sao Suffix Array?

Suffix array sắp xếp tất cả hậu tố của S theo thứ tự từ điển. Mọi xâu con của si đều là tiền tố của một hậu tố bắt đầu trong si. Vì vậy, ta có thể xác định xâu con nào của si cũng xuất hiện trong sj bằng cách kiểm tra hàng xóm trong suffix array.

Thuật toán

Với mỗi hậu tố SA[k] thuộc chuỗi si, gọi là độ dài hậu tố này (tính từ vị trí bắt đầu đến hết si). Các tiền tố của hậu tố này có độ dài từ 1 đến , và tương ứng là các xâu con của si.

Một tiền tố có độ dài d không độc đáo khi nó xuất hiện trong một chuỗi khác, tức là khi nó là tiền tố chung với một hậu tố thuộc sj (ji). Độ dài phần không độc đáo tối đa là:

maxShared(k)=max(LCP với hàng xóm gần nhất bên trái từ chuỗi khác, LCP với hàng xóm gần nhất bên phải từ chuỗi khác)

Vậy hậu tố SA[k] đóng góp vào kết quả:

max(0, maxShared(k))

Ngoài ra, cần tránh đếm trùng xâu con xuất hiện nhiều lần trong si: nếu nhiều hậu tố liên tiếp thuộc cùng chuỗi si trong suffix array, phần LCP giữa chúng được trừ đi để không tính hai lần.

Chi tiết xử lý nhóm

Các hậu tố liên tiếp trong suffix array thuộc cùng chuỗi i tạo thành một "khối". Khi xử lý khối [l,r] (tất cả từ chuỗi i):

  • lmax = LCP với hậu tố ngay trước khối (từ chuỗi khác)
  • Duyệt từ trái sang phải qua khối, cập nhật LCP tích lũy
  • Đóng góp của hậu tố j trong khối: max(0,jmax(lmax,LCP[j]))
  • Cập nhật lmax=min(lmax,LCP[j]) để đảm bảo không đếm trùng

Độ phức tạp

  • Xây dựng suffix array: O(|S|log|S|) với |S|2×105
  • Duyệt suffix array: O(|S|)
  • Tổng: O(|S|log|S|)

Ghi chú cài đặt

  • Ký tự phân cách phải nhỏ hơn a trong thứ tự ASCII để không ảnh hưởng đến sắp xếp (dùng ? hoặc ký tự có mã ASCII thấp).
  • Mảng A[k] lưu cặp (chỉ số chuỗi, độ dài còn lại trong chuỗi đó) cho mỗi vị trí trong S.

Bình luận

Không có bình luận tại thời điểm này.

gnatmake 12.2.0 a68g 3.1.2 nasm 2.16.1 as_x64 2.46 awk 1.3.4 gcc 16.1.0 csc 6.12.0.200 g++ 16.1.0 g++-themis 16.1.0 g++17 16.1.0 g++20 16.1.0 g++23 16.1.0 clang++ 22.1.6 dmd 2.112.0 dart 3.12.1 gforth 0.7.3 gfortran 12.2.0 go 1.26.3 groovyc 5.0.6 javac 25.0.3 node 26.2.0 kotlinc 2.3.21 sbcl 2.2.9 lua 5.4.8 nim 2.2.10 fpc 3.2.2 fpc-themis 3.2.2 perl 5.36.0 php 8.5.6 pike 8.0 pypy3 7.3.23 python3 3.14.5 racket 8.7 ruby 4.0.5 rustc 1.96.0 csc 5.3.0 ctoj-scratch 0.0.1 sed 4.9 tclsh 8.6 bun 1.3.14 deno 2.8.1 v 0.5.1 zig 0.16.0