Problem C solution (passed all pretests) O(n.log(max(A)))
problem 2231C
Instead of tracking everything, we can exploit the fact that numbers shrink incredibly fast under these operations (even 10^9 drops to the bottom cycle in at most around 60 steps).
- Pick initial target `T`: Start by setting `T` to the smallest even number in the array (or `a[0]` if all are odd. Now that im thinking after the contest it could fallback to the smallest number if no even numbers exist).
- Shift the target: Loop through the array. If the current element `a[i]` cannot reach `T`, it means our target is currently too high or on an unreachable branch. Instead of restarting or tracking states, we just reduce our target down
(T = reduce(T))until `a[i]` can reach it. `T` will quickly converge to a matching point. - 1 to 2 check: Since 1 and 2 loop into each other at the bottom, one might save a few extra steps depending on the array. We handle this edge case with a clean, linear check at the very end to see if flipping `T` between 1 and 2 gives a smaller total answer.
```
ll reduce(ll x)
{
if (x%2 == 0) return x/2;
return x+1;
}
bool can_reach(ll x, ll target)
{
for (int i=0; i<100; i++)
{
if (x == target) return true;
x = reduce(x);
}
return false;
}
int get_steps(ll x, ll target)
{
int steps = 0;
while (x != target)
{
x = reduce(x);
steps++;
}
return steps;
}
void solve() {
int n; cin>>n;
vl a(n);
ll T = -1;
for (int i=0; i<n; i++)
{
cin>>a[i];
if (a[i]%2 == 0)
{
if (T==-1 || a[i] <T) T = a[i];
}
}
if (T == -1) T=a[0];
for (int i=0; i<n; i++)
{
while (!can_reach(a[i], T))
{
T = reduce(T);
}
}
ll total_steps = 0;
for (int i = 0; i < n; i++) {
total_steps += get_steps(a[i], T);
}
if (T==2 || T==1)
{
ll alt_target = (T==1)? 2:1;
ll alt_steps = 0;
for (int i=0; i<n; i++) alt_steps += get_steps(a[i], alt_target);
total_steps = min(total_steps, alt_steps);
}
cout << total_steps << "\n";
}ll reduce(ll x)
{
if (x%2 == 0) return x/2;
return x+1;
}
bool can_reach(ll x, ll target)
{
for (int i=0; i<100; i++)
{
if (x == target) return true;
x = reduce(x);
}
return false;
}
int get_steps(ll x, ll target)
{
int steps = 0;
while (x != target)
{
x = reduce(x);
steps++;
}
return steps;
}
void solve() {
int n; cin>>n;
vl a(n);
ll T = -1;
for (int i=0; i<n; i++)
{
cin>>a[i];
if (a[i]%2 == 0)
{
if (T==-1 || a[i] <T) T = a[i];
}
}
if (T == -1) T=a[0];
for (int i=0; i<n; i++)
{
while (!can_reach(a[i], T))
{
T = reduce(T);
}
}
ll total_steps = 0;
for (int i = 0; i < n; i++) {
total_steps += get_steps(a[i], T);
}
if (T==2 || T==1)
{
ll alt_target = (T==1)? 2:1;
ll alt_steps = 0;
for (int i=0; i<n; i++) alt_steps += get_steps(a[i], alt_target);
total_steps = min(total_steps, alt_steps);
}
cout << total_steps << "\n";
}```