Các lượt nộp
    Danh sách bài
    Trang chủ
    Báo lỗi

    solution

    Đề bài: [Trình biên dịch] Bảng băm ký hiệu và đụng độ

    Trong thực tế, bảng ký hiệu của trình biên dịch thường được cài đặt bằng bảng băm (hash table) để tra cứu nhanh. Bài này yêu cầu bạn từ-vựng-hoá mã nguồn để lấy ra các định danh, tính giá trị băm của từng định danh, rồi đếm số cặp định danh bị đụng độ (cùng giá trị băm).

    Cho kích thước bảng băm MMM và một đoạn mã nguồn nhiều dòng. Token hoá đơn giản: một định danh là dãy ký tự khớp mẫu [a-zA-Z_][a-zA-Z0-9_]∗[a\text{-}zA\text{-}Z\_][a\text{-}zA\text{-}Z0\text{-}9\_]^*[a-zA-Z_][a-zA-Z0-9_]∗ (theo maximal munch); mọi ký tự khác trong mã nguồn được bỏ qua hoàn toàn (không có khái niệm từ khoá trong bài này — mọi định danh hợp lệ đều được xét, kể cả khi trùng với từ khoá của ngôn ngữ khác).

    Lấy danh sách các định danh duy nhất theo thứ tự xuất hiện lần đầu tiên trong mã nguồn (đọc từ trên xuống dưới, trái sang phải). Với một định danh s=s0s1…sL−1s = s_0 s_1 \ldots s_{L-1}s=s0​s1​…sL−1​ (dãy ký tự theo đúng thứ tự trong từ), giá trị băm được tính theo công thức đa thức (polynomial rolling hash) cơ số 131131131:

    h(s)=(∑k=0L−1ord(sk)⋅131k) mod Mh(s) = \left(\sum_{k=0}^{L-1} \text{ord}(s_k) \cdot 131^{k}\right) \bmod Mh(s)=(∑k=0L−1​ord(sk​)⋅131k)modM

    trong đó ord(c)\text{ord}(c)ord(c) là mã ASCII của ký tự ccc, và số mũ kkk tăng dần theo vị trí ký tự tính từ đầu từ (vị trí đầu tiên có k=0k = 0k=0).

    Sau khi tính băm cho tất cả định danh duy nhất, hãy đếm số cặp (i,j)(i, j)(i,j) với i<ji < ji<j (theo chỉ số trong danh sách định danh duy nhất) mà h(si)=h(sj)h(s_i) = h(s_j)h(si​)=h(sj​) — đó chính là số cặp đụng độ.

    • Định dạng đầu vào:

      Dòng 1: số nguyên MMM (M≥1M \ge 1M≥1) — kích thước bảng băm. Các dòng tiếp theo (đến hết input): mã nguồn cần phân tích, có thể rỗng (không có dòng nào).

    • Định dạng đầu ra:

      Với mỗi định danh duy nhất, theo đúng thứ tự xuất hiện lần đầu, in một dòng TEN HASH. Dòng cuối cùng (luôn có, kể cả khi không có định danh nào) in DUNG_DO: <số cặp đụng độ>.

    Ví dụ:

    Đầu vào:

    1000003
    int x; int y; x = y + x;
    

    Đầu ra:

    int 5185
    x 120
    y 121
    DUNG_DO: 0
    

    Đầu vào:

    1
    a b c
    

    Đầu ra:

    a 0
    b 0
    c 0
    DUNG_DO: 3
    

    Đang tải editor...