Trong các bài toán tin học các yêu cầu xử lý cần dùng phép toán chia lấy dư (%) rất phổ biến. Rất nhiều bài tốn cần đến xử lí số lớn, nhưng khi ý đồ của tác giả chỉ là tìm ra thuật tốn đúng để giải quyết bài tốn chứ khơng coi trọng việc cài đặt số lớn, lúc đó thường thì đề ra sẽ u cầu ghi ra số dư của kết quả khi chia cho 1 cơ số bất kì nào đó. Vì vậy mà ta cần tìm hiểu các tính chất đồng dư để có thể đảm bảo kết quả mình đưa ra là chính xác.
Giả sử có 2 số nguyên x và y, với cơ số là n, có những tính chất đồng dư sau đây:
1. (x+y)% n = ((x % n)+(y % n)) % n. 2. (x*y)% n =((x % n)*(y % n))%n.
Bài toán cơ bản. Tổng lập phương
Cho số tự nhiên n. Hãy viết chương trình tính S = 13 + 23 + 33 + …+ n3.
Dữ liệu vào:
Đọc từ tệp TLP.Inp gồm một dòng duy nhất chứa số nguyên n (1<=n<=109).
Dữ liệu ra:
Ghi kết quả ra tệp TLP.Out một giá trị duy nhất làị số dư của phép chia S cho 109+7
Ví dụ
TLP.inp TLP.out
3 36
4 100
Ràng buộc: 70% test ứng với giới hạn 1<=n<=104
30% test ứng với các trường hợp còn lại
Ý tưởng:
Cách 1: Sử dụng vòng lặp duyệt các số i từ 1 đến n để tính tổng lập phương.
S=0;
for (int i=1; i<=n; i++) S = s+ i*i*i; S= S%(109+7);
Với cách làm này độ phức tạp là O(n), nếu sử dụng kiểu dữ liệu phù hợp thì ta cũng chỉ mới ăn được các test nhỏ chưa giải quyết được với mọi giá trị. Vì vậy cần tiếp tục cải tiến.
Cách 2: Sử dụng cơng thức tốn học:
Ta có thể chuyển độ phức tạp xuống O(1), nhưng lưu ý rằng giá trị của S là rất lớn, khơng có kiểu dữ liệu nguyên nào có thể lưu lại giá trị kết quả. Vì vậy ta cần vận dụng tính chất đồng dư để giải quyết bài tốn.
Khi đó ta có câu lệnh tính 𝟏𝟑+ 𝟐𝟑 + 𝟑𝟑 + ⋯ + 𝒏𝟑 =𝒏 𝟐(𝒏 + 𝟏)𝟐 𝟒 Khai báo hằng e: e= 109 +7. S = ((n%e)*(n%e))%e)*((n+1)%e)*((n+1)%e)%e)/4;