Thân của một vòng lặp là một khối lệnh tuần tự gồm n câu lệnh dạng x = y op z (op ∈{+,−,∗,/}), 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 y hoặc z là một hằng số nguyên, hoặc tên một biến. Cho trước tập E 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 E 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,z đều thỏa: là hằng số, HOẶC là biến thuộc E, 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ộ n câu lệnh.
Giả sử vòng lặp chạy N lần (N≥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−k câu lệnh còn lại (k = số câu bất biến) vẫn chạy đủ N lần bên trong vòng lặp, hãy tính:
(a) k — 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×n; và SAU khi tối ưu: k+N×(n−k) (lưu ý: nếu N=0, tổng sau tối ưu vẫn bằng k chứ không phải 0, vì k 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).
Dòng 1: hai số nguyên n, N (0≤n≤500, 0≤N≤106). Dòng 2: số nguyên ∣E∣ rồi ∣E∣ tên biến thuộc E, cách nhau khoảng trắng (nếu ∣E∣=0, chỉ có số 0). n 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.
Dòng 1: số nguyên k. 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=0). Dòng 3: hai số nguyên "Tbefore 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...