Sông Tô Lịch là một con sông dài và nổi tiếng ở Hà Nội. Chắc hẳn nhiều bạn đã biết, sông Tô Lịch nổi tiếng bởi hương thơm ngào ngạt, hữu xạ tự nhiên hương, luôn để lại ấn tượng khó phai trong mỗi người đi qua. Chính con sông này đã tạo cho người dân thủ đô thói quen đeo khẩu trang thường xuyên, bởi chỉ một tích tắc bỏ khẩu trang thôi, hương thơm ngây ngất sẽ ùa vào, xâm chiếm lồng ngực người đi qua, khiến cho người đi đường... ngất xỉu. Bởi thế, khi dịch COVID-19 bùng phát, người dân Hà Nội vững vàng chiến thắng đại dịch, nhờ thói quen đeo khẩu trang đã được rèn luyện từ xa xưa. Thế mới thấy, sông Tô Lịch đóng vai trò quan trọng trong công cuộc chống dịch của người dân thủ đô như thế nào.
Nằm trên tuyến đường huyết mạch của thủ đô, sông Tô Lịch có hàng chục cây cầu phục vụ nhu cầu đi qua đi lại. Tuy nhiên, đặc sản tắc đường khiến cư dân vùng ven qua sông như xông pha ra trận mạc. Để khác phục tình trạng này, người dân tạo ra một con đường qua sông mới — qua sông bằng đá. Con đường độc đạo này đảm bảo xe máy không thể đi qua, virus tắc đường không có khả năng bùng phát.
Người dân đặt n+1 hòn đá trên sông. Các hòn đá nằm trên một đường thẳng vuông góc với hai bờ. Các hòn đá lần lượt được đánh số từ 0 đến n theo thứ tự, trong đó hòn đá số 0 nằm ở một bờ và hòn đá số n nằm ở bờ bên kia. Cư dân ở đây chọn ra một số nguyên dương M, và định khoảng cách giữa hai hòn đá liên tiếp như sau: Với mỗi i thỏa mãn &0 ≤ i < n$, khoảng cách giữa hòn đá thứ i và hòn đá thứ i + 1 là .
Ví dụ, với n = 5 và M = 7, ta có , , , , .
Do mùi thơm đặc trưng của dòng sông, người dân không muốn đứng lâu giữa sông để tận hưởng cảm giác ngây ngất. Bởi thế, họ muốn qua sông với không quá j bước nhảy. Tất nhiên, mỗi bước nhảy phải xuất phát từ một hòn đá và nhảy tới hòn đá khác, bước nhảy đầu tiên phải xuất phát từ hòn đá số 0 và bước nhảy cuối cùng phải kết thúc ở hòn đá số n. Các bạn hãy giúp người dân xác định tầm nhảy tối thiểu để giúp họ qua sông. Nói cách khác, tìm số L nhỏ nhất sao cho với không quá j bước nhảy và mỗi bước nhảy có tầm xa không quá L, người dân có thể đi từ hòn đá 0 tới hòn đá n.
Input
Gồm một dòng duy nhất với ba số nguyên n, M và j $(1 ≤ j ≤ n ≤ 10^6, 1 ≤ M ≤ 10^9 + 7)$.
Output
Gồm một số duy nhất là tầm nhảy nhỏ nhất để người dân có thể qua sông sau không quá j bước nhảy.
#define INF (long long)1e16
long long solve(void) {
long long L = 1, R = INF, mid;
while (true) {
if (L == R) return L;
if (R - L == 1) return check(L) ? L : R;
mid = (R + L) >> 1;
if (check(mid) == true) R = mid;
else L = mid + 1;
}
}
int d[1000005], m, limit, n;
//d[i] là khoảng cách từ viên đá thứ i-1 đến viên đá thứ i.
//limit là số bước nhảy lớn nhất.
//n là số viên đá.
//mục tiêu của hàm là kiểm tra xem dist có phải là kết quả của bài toán hay không
bool check(long long dist) {
int i = 0;
long long tmp = 0;
for (int j = 1; j<= limit; j++) {
int k = i;
tmp = 0;
while (k < n && tmp + d[k+1] <= dist) {
tmp += d[k+1];
k++;
}
i = k;
if (i == n) return true;
}
return false;
}
#include <bits/stdc++.h>
#define INF (long long)1e16
using namespace std;
int d[1000005], m, limit, n;
bool check(long long dist) {
int i = 0;
long long tmp = 0;
for (int j = 1; j<= limit; j++) {
int k = i;
tmp = 0;
while (k < n && tmp + d[k+1] <= dist) {
tmp += d[k+1];
k++;
}
i = k;
if (i == n) return true;
}
return false;
}
long long solve(void) {
long long L = 1, R = INF, mid;
while (4 < 5) {
if (L == R) return L;
if (R - L == 1) return check(L) ? L : R;
mid = (R + L) >> 1;
if (check(mid) == true) R = mid;
else L = mid + 1;
}
}
int main()
{
freopen("river.inp", "r", stdin); //Đọc input từ file river.inp
freopen("river.out", "w", stdout); //In ra output tại file river.out
long long ll = 1;
cin >> n >> m >> limit;
//Tính d[i] theo công thức đã cho ở đầu bài, nhắc lại, d[i] là khoảng cách từ hòn đá thứ i-1 đến hòn đá thứ i.
for (int i = 1; i<=n; i++)
d[i] = 1 + (ll*(i-1)*(i-1))%m;
cout << solve(); //In ra kết quả.
return 0;
}
int
, khi đó ta có thể khắc phục bằng cách đổi kiểu dữ liệu của $i$ từ kiểu int
thành kiểu long long
hoặc viết như trên để tránh việc bị tràn số.