Hướng dẫn thuật toán

Trùm CUỐI 2026-01-11 11:06:35

Link bài tập

1. Phân tích bài toán

  • Đây là bài toán tối ưu hóa việc kết hợp các phần tử liên tiếp, tương tự như bài toán Nhân ma trận liên tiếp hoặc Cây nhị phân tìm kiếm tối ưu.
  • Điểm quan trọng: Màu của một hỗn hợp sau khi trộn nhiều thành phần từ chỉ số i đến j luôn bằng:

    \text{Tổng các màu từ } i \text{ đến } j \pmod{100}

    Điều này có nghĩa là dù bạn trộn theo thứ tự nào trong đoạn [i, j] , màu cuối cùng của đoạn đó vẫn không thay đổi.

2. Ý tưởng thuật toán (Quy hoạch động)

Ta gọi dp[i][j] là lượng khói tối thiểu để trộn các hỗn hợp từ vị trí i đến vị trí j .

  • Trạng thái cơ bản: Nếu i = j , dp[i][i] = 0 (một hỗn hợp duy nhất không tạo ra khói).
  • Công thức truy hồi: Để tính dp[i][j] , ta thử chia đoạn [i, j] thành hai đoạn con [i, k] [k+1, j] với i \le k < j . Lượng khói tạo ra sẽ là:

    dp[i][j] = \min_{i \le k < j} \{ dp[i][k] + dp[k+1][j] + (\text{màu đoạn } [i, k] \times \text{màu đoạn } [k+1, j]) \}

  • Kết quả cuối cùng: dp[1][N] .

3. Các bước thực hiện

  1. Tiền xử lý: Xây dựng mảng cộng dồn (prefix sum) để tính nhanh tổng màu của một đoạn bất kỳ từ i đến j . Màu của đoạn [i, j] sẽ là: (sum[j] - sum[i-1]) % 100.
  2. Khởi tạo: Tạo bảng dp kích thước N \times N , lấp đầy bằng một giá trị vô cùng lớn (infinity), các đường chéo chính dp[i][i] = 0 .
  3. Lặp theo độ dài:
    • Duyệt độ dài L từ 2 đến N .
    • Duyệt điểm bắt đầu i từ 1 đến N - L + 1 .
    • Xác định điểm kết thúc j = i + L - 1 .
    • Duyệt điểm chia k từ i đến j-1 để cập nhật dp[i][j] theo công thức truy hồi ở trên.

4. Lưu ý khi triển khai

  • Độ phức tạp: Thuật toán có độ phức tạp O(N^3) . Với N=100 , số phép tính khoảng 100^3 = 1.000.000 , hoàn toàn chạy tốt trong giới hạn thời gian.
  • Kiểu dữ liệu: Tổng lượng khói có thể lớn, nên sử dụng kiểu số nguyên 64-bit (long long trong C++ hoặc mặc định trong Python) để tránh tràn số.
  • Xử lý modulo: Khi tính màu đoạn [i, j] , hãy đảm bảo kết quả của phép chia lấy dư không bị âm (trong C++, công thức an toàn là (sum[j] - sum[i-1]) % 100 nếu tổng luôn dương).