1455B - Jumps
30 Nov 2020 — Tags: math,binary_search — URLNote that we have to make at least $n$ jumps to reach $x$ (always jumping forward), where $n$ is:
\[n = argmin_n(f(n)- x >= 0)\]Where $f(n) = \frac{n \times (n + 1)}{2}$. Intuitively, the answer shouldn’t be much bigger than that.
Furthermore, we know that $0 <= f(n) - x < n$ (because of the $argmin$ constraints). We have to select a subset of our forward steps and turn them into backward steps, or try increasing $n$.
We can think of reversing a step $k$ as decreasing $f(n)$ by $k + 1$. For our range of $[1, n]$, we would have options $[2, n + 1]$.
The problem splits in three cases:
- $f(n) - x = 0$: $n$ is the answer.
- $2 <= f(n) - x < n$: We can reverse the step $f(n) - x - 1$. $n$ is the answer.
- $f(n) - x = 1$: There’s no way to reverse any step from $[1, n]$ to get to $x$, but we can just take the $n + 1$ step backward. $n + 1$ is the answer.
Time complexity: $O(\log{n})$
Memory complexity: $O(1)$
Click to show code.
using namespace std;
using ll = long long;
using ii = pair<int, int>;
using vi = vector<int>;
using predicate = function<bool(ll)>;
inline ll f(ll n) { return (n * (n + 1)) / 2; }
ll bs(ll l, ll r, predicate p)
{
while (l < r)
{
ll m = l + (r - l) / 2;
if (p(m))
r = m;
else
l = m + 1;
}
return l;
}
int main(void)
{
ios::sync_with_stdio(false), cin.tie(NULL);
int t;
cin >> t;
while (t--)
{
ll x;
cin >> x;
auto ok = [x](ll n) { return f(n) >= x; };
int n = bs(1, x, ok);
if (f(n) - x == 1)
cout << n + 1 << endl;
else
cout << n << endl;
}
return 0;
}