Hướng dẫn giải của Educational Backtracking: Xâu đầy đủ


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.
  • Ta có nhận xét rằng, nếu sử dụng cách sinh nhị phân các xâu được chọn ra rồi ghép từng xâu vào để kiểm tra sẽ cho độ phức tạp ~O(2^n*n)~, với ~n = 25~ thì sẽ dẫn tới chạy quá thời gian.
  • Để tối ưu thuật toán, ta thấy rằng mỗi xâu có thể được lưu dưới dạng một số nguyên ~mask~ gồm ~26~ bit, nếu bit thứ ~i~ bật thì nghĩa là trong xâu đó có xuất hiện kí tự thứ ~i~ trong bảng chữ cái (kí tự ~'a'~ được tính là kí tự thứ ~0~).
  • Như vậy, ta cần tìm cách chọn ra một tập xâu sao cho tổng ~or~ của các ~mask~ đại diện cho xâu đó bằng với ~2^{26}-1~.
  • Để tránh việc ta phải sinh ra một dãy nhị phân rồi mới bắt đầu xét từng phần tử trong đó để tính tổng ~or~, ta có thể tạo một hàm:
void ql(int id, int val) {
    // id là vị trí xâu đang xét tới, val là tổng or của các xâu đã được chọn
    // nếu val = 2^(26)-1 thì tăng kết quả lên 1
    if (val == need) res++;
    // thực hiện quay lui nhị phân như bình thường
    if (id > n) return;
    // nếu chọn xâu id
    ql(id + 1, val | mask\[id\]);
    // nếu không chọn xâu id
    ql(id + 1, val);
}

Như vậy ta sẽ thu được thuật toán có độ phức tạp ~O(2^n)~.


Bình luận

Hãy đọc nội quy trước khi bình luận.


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