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] Ước lượng chi phí sau khi di chuyển mã bất biến vòng lặp

    Thân của một vòng lặp là một khối lệnh tuần tự gồm nnn câu lệnh dạng x = y op z (op ∈{+,−,∗,/}\in \{+,-,*,/\}∈{+,−,∗,/}), trong đó mỗi biến chỉ được ĐỊNH NGHĨA (xuất hiện ở vế trái) đúng MỘT lần duy nhất trong toàn thân vòng lặp (dạng SSA cục bộ — thứ tự các câu lệnh trong danh sách không nhất thiết phản ánh thứ tự phụ thuộc). Mỗi toán hạng yyy hoặc zzz là một hằng số nguyên, hoặc tên một biến. Cho trước tập EEE gồm các biến "bên ngoài vòng lặp" — giá trị của các biến này không đổi qua mọi lần lặp (ví dụ: hằng số toàn cục, biến chỉ gán trước vòng lặp). Bất kỳ biến nào KHÔNG thuộc EEE và cũng KHÔNG được định nghĩa bởi thân vòng lặp (ví dụ biến đếm vòng lặp, hay một biến tích lũy được cập nhật ở nơi khác) được xem là thay đổi mỗi lần lặp — KHÔNG bất biến.

    Một câu lệnh x = y op z là bất biến vòng lặp (loop-invariant) khi và chỉ khi cả hai toán hạng y,zy, zy,z đều thỏa: là hằng số, HOẶC là biến thuộc EEE, HOẶC là biến được định nghĩa bởi một câu lệnh KHÁC trong thân vòng lặp mà câu lệnh đó CŨNG đã được xác định là bất biến. Tính chất này lan truyền theo dây chuyền nên cần áp dụng lặp tới điểm cố định qua toàn bộ nnn câu lệnh.

    Giả sử vòng lặp chạy NNN lần (N≥0N \ge 0N≥0). Nếu tất cả câu lệnh bất biến được "kéo" (hoist) ra ngoài vòng lặp — chỉ tính một lần duy nhất, VÔ ĐIỀU KIỆN (dù vòng lặp có thực sự chạy lần nào hay không) — trong khi n−kn-kn−k câu lệnh còn lại (kkk = số câu bất biến) vẫn chạy đủ NNN lần bên trong vòng lặp, hãy tính:

    (a) kkk — số câu lệnh bất biến tìm được, và danh sách chỉ số (1-indexed, theo thứ tự xuất hiện trong input) của các câu lệnh đó, tăng dần.

    (b) Tổng số lượt thực thi câu lệnh TRƯỚC khi tối ưu: N×nN \times nN×n; và SAU khi tối ưu: k+N×(n−k)k + N \times (n - k)k+N×(n−k) (lưu ý: nếu N=0N = 0N=0, tổng sau tối ưu vẫn bằng kkk chứ không phải 000, vì kkk câu lệnh đã bị kéo ra chạy vô điều kiện một lần — đây chính là rủi ro thực tế cần cân nhắc khi áp dụng LICM cho các phép toán có thể gây lỗi, dù đề bài giả định mọi phép toán ở đây luôn an toàn).

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

      Dòng 1: hai số nguyên nnn, NNN (0≤n≤5000 \le n \le 5000≤n≤500, 0≤N≤1060 \le N \le 10^60≤N≤106). Dòng 2: số nguyên ∣E∣|E|∣E∣ rồi ∣E∣|E|∣E∣ tên biến thuộc EEE, cách nhau khoảng trắng (nếu ∣E∣=0|E|=0∣E∣=0, chỉ có số 0). nnn dòng tiếp theo, mỗi dòng một câu lệnh x = y op z của thân vòng lặp.

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

      Dòng 1: số nguyên kkk. Dòng 2: danh sách chỉ số các câu lệnh bất biến, tăng dần, cách nhau khoảng trắng (dòng trống nếu k=0k=0k=0). Dòng 3: hai số nguyên "TbeforeT_{before}Tbefore​ TafterT_{after}Tafter​" — tổng lượt thực thi trước và sau tối ưu, cách nhau một khoảng trắng.

    Ví dụ:

    Đầu vào:

    0 5
    0
    

    Đầu ra:

    0
    
    0 0
    

    Đầu vào:

    4 3
    1 a
    t1 = a + 5
    t2 = t1 * 2
    t3 = i + t2
    t4 = t1 + t1
    

    Đầu ra:

    3
    1 2 4
    12 6
    

    Đang tải editor...