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.
Hướng tiếp cận
Bài toán yêu cầu cộng một cấp số cộng vào một đoạn của mảng nhiều lần, sau đó in mảng kết quả. Với mảng hiệu bậc một thông thường, ta chỉ xử lý được cập nhật hằng số trên đoạn ( += ). Để xử lý cập nhật tuyến tính theo , ta dùng mảng hiệu bậc hai: lấy hiệu một lần nữa từ mảng hiệu bậc một. Khi đó một cấp số cộng trên đoạn trở thành chỉ thao tác trên mảng hiệu bậc hai.
Nhận xét quan trọng
- Mảng hiệu bậc một (với ). Cập nhật += trên sẽ làm:
- tăng thêm (vì tăng thêm trong khi không đổi).
- Với : tăng thêm (vì hiệu của hai số hạng liên tiếp trong cấp số cộng là ).
- giảm (vì không đổi, còn tăng thêm ).
- Trên , cập nhật "cộng cho mọi " lại là một cập nhật hằng số trên đoạn — ta xử lý bằng mảng hiệu bậc hai .
- Vậy mỗi thao tác chỉ tác động lên vị trí của .
Thuật toán
Khởi tạo mảng . Với mỗi thao tác :
- — báo cho tăng thêm .
- — báo cho tăng thêm thay vì (chênh lệch là ).
- , tức là trừ đi — báo cho giảm (so với vốn tăng , chênh lệch là ).
- — báo cho trở về (so với ).
Sau khi xử lý hết thao tác, lấy tổng tiền tố hai lần:
- với .
- với .
In ra .
Vì sao bốn phép cộng là đúng? Khi lấy tổng tiền tố :
- (chỉ đóng góp).
- .
- với (không có nào khác trong đoạn này).
- .
- .
Lấy tổng tiền tố thêm một lần ra :
- , , ..., — đúng cấp số cộng.
- , , ...
Đúng như mong đợi: chỉ đoạn bị thay đổi và bị cộng đúng cấp số cộng.
Lưu ý tràn số: Giá trị có thể lớn cỡ , và sau cập nhật giá trị tích lũy có thể đến — vượt khỏi long long. Tuy nhiên đề bài đã đảm bảo kết quả cuối nằm trong long long, nên với phép tính modulo (đặc trưng của số có dấu trong C/C++) các kết quả trung gian "tràn" sẽ tự khử lẫn nhau khi tổng tiền tố và cho ra kết quả đúng. Để an toàn, ta dùng kiểu long long (hoặc unsigned long long) cho mảng .
Độ phức tạp
- Thời gian: .
- Bộ nhớ: .
Bình luận